From f24d1143b96e24429b2170f58ed23606b4caa1e8 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Tue, 24 Mar 2026 16:22:53 +0100 Subject: [PATCH 1/3] e2e test framework moved to generic cli. --- go.mod | 8 +- go.sum | 8 +- testing/e2e/test_cmd.go | 5 +- testing/e2e/test_framework.go | 373 ---------------------------- tests/e2e/admin/component_test.go | 9 +- tests/e2e/admin/project_test.go | 5 +- tests/e2e/admin/switch_test.go | 9 +- tests/e2e/admin/tenant_test.go | 7 +- tests/e2e/admin/token_test.go | 7 +- tests/e2e/api/audit_test.go | 7 +- tests/e2e/api/health_test.go | 5 +- tests/e2e/api/image_test.go | 7 +- tests/e2e/api/ip_test.go | 35 +-- tests/e2e/api/project_test.go | 21 +- tests/e2e/api/tenant_test.go | 7 +- tests/e2e/api/token_test.go | 7 +- tests/e2e/testresources/projects.go | 2 +- tests/e2e/testresources/tenants.go | 2 +- tests/e2e/testresources/tokens.go | 2 +- 19 files changed, 83 insertions(+), 443 deletions(-) delete mode 100644 testing/e2e/test_framework.go diff --git a/go.mod b/go.mod index 2b5dd36..9de5756 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,19 @@ module github.com/metal-stack/cli go 1.26 require ( - buf.build/go/protoyaml v0.6.0 connectrpc.com/connect v1.19.1 connectrpc.com/validate v0.6.0 github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.7.0 github.com/metal-stack/api v0.0.58 - github.com/metal-stack/metal-lib v0.24.0 + github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f github.com/metal-stack/v v1.0.3 github.com/spf13/afero v1.15.0 github.com/spf13/cobra v1.10.2 - github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 - google.golang.org/grpc v1.79.1 + google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 sigs.k8s.io/yaml v1.6.0 ) @@ -25,6 +23,7 @@ require ( require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect buf.build/go/protovalidate v1.1.3 // indirect + buf.build/go/protoyaml v0.6.0 // indirect cel.dev/expr v0.25.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -59,6 +58,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.mongodb.org/mongo-driver v1.17.9 // indirect diff --git a/go.sum b/go.sum index d420c4c..5f7458d 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjc github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/metal-stack/api v0.0.58 h1:7UxnZrM41BS0f4S9RvqDg0/YTvs3FveawuyBoKz9WhA= github.com/metal-stack/api v0.0.58/go.mod h1:hEgtKVD7UnUwUExdA7pbFvVRxNRxSGUnU+bZce46//c= -github.com/metal-stack/metal-lib v0.24.0 h1:wvQQPWIXcA2tP+I6zAHUNdtVLLJfQnnV9yG2SoqUkz4= -github.com/metal-stack/metal-lib v0.24.0/go.mod h1:oITaqj/BtB9vDKM66jCXkeA+4D0eTZElgIKal5vtiNY= +github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f h1:qTEfCIrCsE8YTSIhMiI2jYlDqO20K3S4pCNkB9wB3vQ= +github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f/go.mod h1:u1wQl98JOfzyXqY7+0qD2xFSMnxvzCykkLgW80U1IrA= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/minio/minlz v1.1.0 h1:rUOGu3EP4EqJC5k3qCsIwEnZiJULKqtRyDdqbhlvMmQ= @@ -137,8 +137,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= -google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/testing/e2e/test_cmd.go b/testing/e2e/test_cmd.go index 93504f4..c8a24ca 100644 --- a/testing/e2e/test_cmd.go +++ b/testing/e2e/test_cmd.go @@ -1,4 +1,4 @@ -package e2e +package e2erootcmd import ( "bytes" @@ -12,6 +12,7 @@ import ( "github.com/metal-stack/cli/cmd" "github.com/metal-stack/cli/cmd/completion" "github.com/metal-stack/cli/cmd/config" + e2e_test "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/stretchr/testify/require" @@ -23,7 +24,7 @@ type TestConfig struct { ClientCalls []client.ClientCall } -func NewRootCmd(t *testing.T, c *TestConfig) NewRootCmdFunc { +func NewRootCmd(t *testing.T, c *TestConfig) e2e_test.NewRootCmdFunc { return func() (*cobra.Command, *bytes.Buffer) { interceptors := []connect.Interceptor{ client.NewTestInterceptor(t, c.ClientCalls), diff --git a/testing/e2e/test_framework.go b/testing/e2e/test_framework.go deleted file mode 100644 index af794df..0000000 --- a/testing/e2e/test_framework.go +++ /dev/null @@ -1,373 +0,0 @@ -package e2e - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "strings" - "testing" - "testing/synctest" - "time" - - "slices" - - "buf.build/go/protoyaml" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/metal-stack/metal-lib/pkg/pointer" - "github.com/metal-stack/metal-lib/pkg/testcommon" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoimpl" - "google.golang.org/protobuf/testing/protocmp" - "sigs.k8s.io/yaml" -) - -const ( - InputFilePath = "/file.yaml" -) - -// NewRootCmdFunc returns the root command for the cli and an output buffer which returns the output after command execution -type NewRootCmdFunc func() (rootCmd *cobra.Command, out *bytes.Buffer) - -type Test[Response, RawObject any] struct { - Name string - - NewRootCmd NewRootCmdFunc - CmdArgs []string - Out *bytes.Buffer - - AssertExhaustiveArgs bool - AssertExhaustiveExcludes []string - - // output format tests - WantObject RawObject // for rawyaml / rawjson printer - WantProtoObject proto.Message // for yaml / json printer - WantTable *string // for table printer - WantWideTable *string // for wide table printer - WantMarkdown *string // for markdown printer - WantTemplate *string // for template printer - Template *string // for template printer - - WantErr error -} - -func TimeBubbleStartTime() time.Time { - return time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) -} - -func (c *Test[Response, RawObject]) TestCmd(t *testing.T) { - require.NotEmpty(t, c.Name, "test name must not be empty") - require.NotEmpty(t, c.CmdArgs, "cmd must not be empty") - - if c.AssertExhaustiveArgs { - c.assertExhaustiveArgs(t) - } - - if c.WantErr != nil { - rootCmd, _ := c.NewRootCmd() - - os.Args = append([]string{rootCmd.Use}, c.CmdArgs...) - - synctest.Test(t, func(t *testing.T) { - err := rootCmd.Execute() - if diff := cmp.Diff(c.WantErr, err, testcommon.IgnoreUnexported(), testcommon.ErrorStringComparer()); diff != "" { - t.Errorf("error diff (+got -want):\n %s", diff) - } - }) - } - - formats := outputFormats(c) - - if len(formats) == 0 { - t.Errorf("at least one want section for output formats must be specified, otherwise no command is getting executed") - return - } - - for _, format := range formats { - succeeded := t.Run(fmt.Sprintf("%v", format.Args()), func(t *testing.T) { - rootCmd, out := c.NewRootCmd() - - os.Args = append([]string{rootCmd.Use}, c.CmdArgs...) - os.Args = append(os.Args, format.Args()...) - - synctest.Test(t, func(t *testing.T) { - err := rootCmd.Execute() - require.NoError(t, err) - }) - - format.Validate(t, out.Bytes()) - }) - - if !succeeded { - t.FailNow() - } - } -} - -func (c *Test[Response, RawObject]) assertExhaustiveArgs(t *testing.T) { - assertContainsPrefix := func(ss []string, prefix string) error { - for _, s := range ss { - if strings.HasPrefix(s, prefix) { - return nil - } - } - return fmt.Errorf("not exhaustive: does not contain %q", prefix) - } - - rootCmd, _ := c.NewRootCmd() - - cmd, args, err := rootCmd.Find(c.CmdArgs) - require.NoError(t, err) - - cmd.LocalFlags().VisitAll(func(f *pflag.Flag) { - if slices.Contains(c.AssertExhaustiveExcludes, f.Name) { - return - } - - require.NoError(t, assertContainsPrefix(args, "--"+f.Name), "ensure all available args are used in order to increase coverage") - }) -} - -func outputFormats[Response, RawObject any](c *Test[Response, RawObject]) []outputFormat { - var formats []outputFormat - - if !pointer.IsZero(c.WantObject) { - formats = append(formats, - &rawYamlOutputFormat[RawObject]{want: c.WantObject}, - &rawJsonOutputFormat[RawObject]{want: c.WantObject}, - ) - } - - if c.WantProtoObject != nil { - formats = append(formats, - &protoYAMLOutputFormat[Response]{want: c.WantProtoObject}, - &protoJSONOutputFormat[Response]{want: c.WantProtoObject}, - ) - } - - if c.WantTable != nil { - formats = append(formats, &tableOutputFormat{table: *c.WantTable}) - } - - if c.WantWideTable != nil { - formats = append(formats, &wideTableOutputFormat{table: *c.WantWideTable}) - } - - if c.Template != nil && c.WantTemplate != nil { - formats = append(formats, &templateOutputFormat{template: *c.Template, templateOutput: *c.WantTemplate}) - } - - if c.WantMarkdown != nil { - formats = append(formats, &markdownOutputFormat{table: *c.WantMarkdown}) - } - - return formats -} - -type outputFormat interface { - Args() []string - Validate(t *testing.T, output []byte) -} - -type rawYamlOutputFormat[R any] struct { - want R -} - -func (o *rawYamlOutputFormat[R]) Args() []string { - return []string{"-o", "yamlraw"} -} - -func (o *rawYamlOutputFormat[R]) Validate(t *testing.T, output []byte) { - t.Logf("got following yamlraw output:\n\n%s\n", string(output)) - - var got R - - err := yaml.Unmarshal(output, &got) - require.NoError(t, err) - - if diff := cmp.Diff(o.want, got, testcommon.IgnoreUnexported(), cmpopts.IgnoreTypes(protoimpl.MessageState{})); diff != "" { - t.Errorf("diff (+got -want):\n %s", diff) - } -} - -type rawJsonOutputFormat[R any] struct { - want R -} - -func (o *rawJsonOutputFormat[R]) Args() []string { - return []string{"-o", "jsonraw"} -} - -func (o *rawJsonOutputFormat[R]) Validate(t *testing.T, output []byte) { - t.Logf("got following jsonraw output:\n\n%s\n", string(output)) - - var got R - - err := json.Unmarshal(output, &got) - require.NoError(t, err) - - if diff := cmp.Diff(o.want, got, testcommon.IgnoreUnexported(), cmpopts.IgnoreTypes(protoimpl.MessageState{})); diff != "" { - t.Errorf("diff (+got -want):\n %s", diff) - } -} - -type protoYAMLOutputFormat[R any] struct { - want proto.Message -} - -func (o *protoYAMLOutputFormat[R]) Args() []string { - return []string{"-o", "yaml"} -} - -func (o *protoYAMLOutputFormat[R]) Validate(t *testing.T, output []byte) { - t.Logf("got following yaml output:\n\n%s\n", string(output)) - - got := proto.Clone(o.want) - proto.Reset(got) - - err := protoyaml.Unmarshal(output, got) - require.NoError(t, err) - - if diff := cmp.Diff(o.want, got, protocmp.Transform(), testcommon.IgnoreUnexported(), cmpopts.IgnoreTypes(protoimpl.MessageState{})); diff != "" { - t.Errorf("diff (+got -want):\n %s", diff) - } -} - -type protoJSONOutputFormat[R any] struct { - want proto.Message -} - -func (o *protoJSONOutputFormat[R]) Args() []string { - return []string{"-o", "json"} -} - -func (o *protoJSONOutputFormat[R]) Validate(t *testing.T, output []byte) { - t.Logf("got following json output:\n\n%s\n", string(output)) - - got := proto.Clone(o.want) - proto.Reset(got) - - err := protojson.Unmarshal(output, got) - require.NoError(t, err) - - if diff := cmp.Diff(o.want, got, protocmp.Transform(), testcommon.IgnoreUnexported(), cmpopts.IgnoreTypes(protoimpl.MessageState{})); diff != "" { - t.Errorf("diff (+got -want):\n %s", diff) - } -} - -type tableOutputFormat struct { - table string -} - -func (o *tableOutputFormat) Args() []string { - return []string{"-o", "table"} -} - -func (o *tableOutputFormat) Validate(t *testing.T, output []byte) { - validateTableRows(t, o.table, string(output)) -} - -type wideTableOutputFormat struct { - table string -} - -func (o *wideTableOutputFormat) Args() []string { - return []string{"-o", "wide"} -} - -func (o *wideTableOutputFormat) Validate(t *testing.T, output []byte) { - validateTableRows(t, o.table, string(output)) -} - -type templateOutputFormat struct { - template string - templateOutput string -} - -func (o *templateOutputFormat) Args() []string { - return []string{"-o", "template", "--template", o.template} -} - -func (o *templateOutputFormat) Validate(t *testing.T, output []byte) { - t.Logf("got following template output:\n\n%s\n\nconsider using this for test comparison if it looks correct.", string(output)) - - if diff := cmp.Diff(strings.TrimSpace(o.templateOutput), strings.TrimSpace(string(output))); diff != "" { - t.Errorf("diff (+got -want):\n %s", diff) - } -} - -type markdownOutputFormat struct { - table string -} - -func (o *markdownOutputFormat) Args() []string { - return []string{"-o", "markdown"} -} - -func (o *markdownOutputFormat) Validate(t *testing.T, output []byte) { - validateTableRows(t, o.table, string(output)) -} - -func validateTableRows(t *testing.T, want, got string) { - trimAll := func(ss []string) []string { - var res []string - for _, s := range ss { - res = append(res, strings.TrimSpace(s)) - } - return res - } - - var ( - trimmedWant = strings.TrimSpace(want) - trimmedGot = strings.TrimSpace(string(got)) - - wantRows = trimAll(strings.Split(trimmedWant, "\n")) - gotRows = trimAll(strings.Split(trimmedGot, "\n")) - ) - - t.Logf("got following table output:\n\n%s\n\nconsider using this for test comparison if it looks correct.", trimmedGot) - - // somehow this diff does not look nice anymore. :( - // t.Log(cmp.Diff(trimmedWant, trimmedGot)) - - require.Equal(t, len(wantRows), len(gotRows), "tables have different lengths") - - for i := range wantRows { - wantFields := trimAll(strings.Split(wantRows[i], " ")) - gotFields := trimAll(strings.Split(gotRows[i], " ")) - - require.Equal(t, len(wantFields), len(gotFields), "table fields have different lengths") - - for i := range wantFields { - assert.Equal(t, wantFields[i], gotFields[i]) - } - } -} - -func CommonExcludedFileArgs() []string { - return []string{"file", "bulk-output", "skip-security-prompts", "timestamps"} -} - -func AppendFromFileCommonArgs(args ...string) []string { - return append(args, []string{"-f", InputFilePath, "--skip-security-prompts", "--bulk-output"}...) -} - -func MustMarshal(t *testing.T, d any) []byte { - b, err := json.MarshalIndent(d, "", " ") - require.NoError(t, err) - return b -} - -func MustMarshalToMultiYAML(t *testing.T, data ...any) []byte { - var parts []string - for _, elem := range data { - parts = append(parts, string(MustMarshal(t, elem))) - } - return []byte(strings.Join(parts, "\n---\n")) -} diff --git a/tests/e2e/admin/component_test.go b/tests/e2e/admin/component_test.go index cd9c43b..ebf66b8 100644 --- a/tests/e2e/admin/component_test.go +++ b/tests/e2e/admin/component_test.go @@ -8,7 +8,8 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -55,7 +56,7 @@ func Test_AdminComponentCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"admin", "component", "describe", component1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ComponentServiceGetRequest{ @@ -100,7 +101,7 @@ func Test_AdminComponentCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "component", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ComponentServiceListRequest{ @@ -150,7 +151,7 @@ func Test_AdminComponentCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"admin", "component", "delete", component1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ComponentServiceDeleteRequest{ diff --git a/tests/e2e/admin/project_test.go b/tests/e2e/admin/project_test.go index 357e227..423a49c 100644 --- a/tests/e2e/admin/project_test.go +++ b/tests/e2e/admin/project_test.go @@ -7,8 +7,9 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_AdminProjectCmd_List(t *testing.T) { @@ -16,7 +17,7 @@ func Test_AdminProjectCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "project", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ProjectServiceListRequest{}, diff --git a/tests/e2e/admin/switch_test.go b/tests/e2e/admin/switch_test.go index 1cd9985..3a7086a 100644 --- a/tests/e2e/admin/switch_test.go +++ b/tests/e2e/admin/switch_test.go @@ -8,7 +8,8 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -65,7 +66,7 @@ func Test_AdminSwitchCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"admin", "switch", "describe", switch1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceGetRequest{ @@ -93,7 +94,7 @@ func Test_AdminSwitchCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "switch", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceListRequest{ @@ -145,7 +146,7 @@ func Test_AdminSwitchCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"admin", "switch", "delete", switch1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceDeleteRequest{ diff --git a/tests/e2e/admin/tenant_test.go b/tests/e2e/admin/tenant_test.go index 3914611..5b8cf43 100644 --- a/tests/e2e/admin/tenant_test.go +++ b/tests/e2e/admin/tenant_test.go @@ -7,7 +7,8 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -41,7 +42,7 @@ func Test_AdminTenantCmd_Create(t *testing.T) { { Name: "create", CmdArgs: []string{"admin", "tenant", "create", "--name", adminTenant1().Name, "--description", adminTenant1().Description, "--email", adminTenant1().Email}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TenantServiceCreateRequest{ @@ -71,7 +72,7 @@ func Test_AdminTenantCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "tenant", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TenantServiceListRequest{}, diff --git a/tests/e2e/admin/token_test.go b/tests/e2e/admin/token_test.go index 13b079b..136a50b 100644 --- a/tests/e2e/admin/token_test.go +++ b/tests/e2e/admin/token_test.go @@ -7,8 +7,9 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_AdminTokenCmd_List(t *testing.T) { @@ -16,7 +17,7 @@ func Test_AdminTokenCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "token", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TokenServiceListRequest{}, @@ -64,7 +65,7 @@ func Test_AdminTokenCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"admin", "token", "delete", testresources.Token1().Uuid, "--user", "user-123"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TokenServiceRevokeRequest{ diff --git a/tests/e2e/api/audit_test.go b/tests/e2e/api/audit_test.go index dfe062e..dc7afd5 100644 --- a/tests/e2e/api/audit_test.go +++ b/tests/e2e/api/audit_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -48,7 +49,7 @@ func Test_AuditCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"audit", "list", "--tenant", "a"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceListRequest{ @@ -100,7 +101,7 @@ func Test_AuditCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"audit", "describe", "--tenant", "a", Trace1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceGetRequest{ diff --git a/tests/e2e/api/health_test.go b/tests/e2e/api/health_test.go index 1562a1e..08f845e 100644 --- a/tests/e2e/api/health_test.go +++ b/tests/e2e/api/health_test.go @@ -6,7 +6,8 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) var ( @@ -28,7 +29,7 @@ func Test_HealthCmd(t *testing.T) { { Name: "health", CmdArgs: []string{"health"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.HealthServiceGetRequest{}, diff --git a/tests/e2e/api/image_test.go b/tests/e2e/api/image_test.go index 2419326..14c13af 100644 --- a/tests/e2e/api/image_test.go +++ b/tests/e2e/api/image_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_ImageCmd_List(t *testing.T) { @@ -15,7 +16,7 @@ func Test_ImageCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"image", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ImageServiceListRequest{ @@ -66,7 +67,7 @@ func Test_ImageCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"image", "describe", testresources.Image1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ImageServiceGetRequest{ diff --git a/tests/e2e/api/ip_test.go b/tests/e2e/api/ip_test.go index d7fa668..45053f2 100644 --- a/tests/e2e/api/ip_test.go +++ b/tests/e2e/api/ip_test.go @@ -7,8 +7,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) @@ -18,7 +19,7 @@ func Test_IPCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"ip", "list", "--project", testresources.IP1().Project}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.IPServiceListRequest{ @@ -68,7 +69,7 @@ func Test_IPCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"ip", "describe", "--project", testresources.IP1().Project, testresources.IP1().Ip}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.IPServiceGetRequest{ @@ -114,7 +115,7 @@ func Test_IPCmd_Create(t *testing.T) { { Name: "create", CmdArgs: []string{"ip", "create", "--project", testresources.IP1().Project, "--network", testresources.IP1().Network, "--static=true"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.IPServiceCreateRequest{ @@ -135,8 +136,8 @@ func Test_IPCmd_Create(t *testing.T) { { Name: "create from file", CmdArgs: append([]string{"ip", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.IP1()), 0755)) }, @@ -187,7 +188,7 @@ func Test_IPCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"ip", "delete", "--project", testresources.IP1().Project, testresources.IP1().Ip}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.IPServiceDeleteRequest{ @@ -207,8 +208,8 @@ func Test_IPCmd_Delete(t *testing.T) { { Name: "delete from file", CmdArgs: append([]string{"ip", "delete"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.IP1()), 0755)) }, @@ -254,8 +255,8 @@ func Test_IPCmd_Update(t *testing.T) { { Name: "update", CmdArgs: []string{"ip", "update", "--project", testresources.IP1().Project, testresources.IP1().Ip, "--name", "foo"}, - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ // TODO: the client gets the IP two times? { @@ -307,8 +308,8 @@ func Test_IPCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"ip", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.IP1()), 0755)) }, @@ -360,8 +361,8 @@ func Test_IPCmd_Apply(t *testing.T) { { Name: "apply", CmdArgs: append([]string{"ip", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.IP1()), 0755)) }, @@ -405,8 +406,8 @@ func Test_IPCmd_Apply(t *testing.T) { { Name: "apply already exists", CmdArgs: append([]string{"ip", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.IP1()), 0755)) }, diff --git a/tests/e2e/api/project_test.go b/tests/e2e/api/project_test.go index 2d748ea..343bf1b 100644 --- a/tests/e2e/api/project_test.go +++ b/tests/e2e/api/project_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) @@ -17,7 +18,7 @@ func Test_ProjectCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"project", "describe", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceGetRequest{ @@ -62,7 +63,7 @@ func Test_ProjectCmd_Create(t *testing.T) { { Name: "create", CmdArgs: []string{"project", "create", "--name", testresources.Project1().Name, "--description", testresources.Project1().Description, "--tenant", testresources.Project1().Tenant}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceCreateRequest{ @@ -84,7 +85,7 @@ func Test_ProjectCmd_Create(t *testing.T) { { Name: "create from file", CmdArgs: append([]string{"project", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) }, @@ -111,7 +112,7 @@ func Test_ProjectCmd_Create(t *testing.T) { { Name: "create many from file", CmdArgs: append([]string{"project", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshalToMultiYAML(t, testresources.Project1(), testresources.Project2()), 0755)) }, @@ -159,7 +160,7 @@ func Test_ProjectCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"project", "delete", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceDeleteRequest{ @@ -178,7 +179,7 @@ func Test_ProjectCmd_Delete(t *testing.T) { { Name: "delete from file", CmdArgs: append([]string{"project", "delete"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) }, @@ -211,7 +212,7 @@ func Test_ProjectCmd_Update(t *testing.T) { { Name: "update", CmdArgs: []string{"project", "update", testresources.Project1().Uuid, "--name", "new-name", "--description", "new-desc"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceUpdateRequest{ @@ -232,7 +233,7 @@ func Test_ProjectCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"project", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) }, @@ -267,7 +268,7 @@ func Test_ProjectCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"project", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceListRequest{}, diff --git a/tests/e2e/api/tenant_test.go b/tests/e2e/api/tenant_test.go index 3936dc2..7935e9b 100644 --- a/tests/e2e/api/tenant_test.go +++ b/tests/e2e/api/tenant_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_TenantCmd_Describe(t *testing.T) { @@ -15,7 +16,7 @@ func Test_TenantCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"tenant", "describe", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceGetRequest{ @@ -60,7 +61,7 @@ func Test_TenantCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"tenant", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceListRequest{}, diff --git a/tests/e2e/api/token_test.go b/tests/e2e/api/token_test.go index d02766e..77ad210 100644 --- a/tests/e2e/api/token_test.go +++ b/tests/e2e/api/token_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_TokenCmd_Describe(t *testing.T) { @@ -15,7 +16,7 @@ func Test_TokenCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"token", "describe", testresources.Token1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TokenServiceGetRequest{ @@ -60,7 +61,7 @@ func Test_TokenCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"token", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TokenServiceListRequest{}, diff --git a/tests/e2e/testresources/projects.go b/tests/e2e/testresources/projects.go index 3f06a38..c1c107e 100644 --- a/tests/e2e/testresources/projects.go +++ b/tests/e2e/testresources/projects.go @@ -2,7 +2,7 @@ package testresources import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/tenants.go b/tests/e2e/testresources/tenants.go index 05b958b..9226681 100644 --- a/tests/e2e/testresources/tenants.go +++ b/tests/e2e/testresources/tenants.go @@ -2,7 +2,7 @@ package testresources import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/tokens.go b/tests/e2e/testresources/tokens.go index b3349d6..fcfa890 100644 --- a/tests/e2e/testresources/tokens.go +++ b/tests/e2e/testresources/tokens.go @@ -4,7 +4,7 @@ import ( "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" ) From 479ee2bebc040652089a538a7b97c67089a2c7f1 Mon Sep 17 00:00:00 2001 From: Anna Schreiner Date: Wed, 3 Jun 2026 11:34:19 +0200 Subject: [PATCH 2/3] Merge branch 'main' into e2e-framework-move --- .github/release-drafter.yml | 30 - .github/workflows/docker.yaml | 26 +- .github/workflows/release-drafter.yaml | 15 - Makefile | 6 +- cmd/admin/v2/commands.go | 4 +- cmd/admin/v2/image.go | 105 +++- cmd/admin/v2/task.go | 125 ++++ cmd/api/v2/ip.go | 109 ++-- cmd/api/v2/project.go | 8 +- cmd/api/v2/tenant.go | 16 +- cmd/login.go | 2 +- cmd/sorters/task.go | 35 ++ cmd/tableprinters/common.go | 12 + cmd/tableprinters/switch.go | 2 +- cmd/tableprinters/switch_test.go | 2 +- cmd/tableprinters/task.go | 74 +++ cmd/tableprinters/user.go | 50 ++ docs/metalctlv2.md | 2 +- docs/metalctlv2_api-methods.md | 2 +- docs/metalctlv2_audit.md | 2 +- docs/metalctlv2_audit_describe.md | 2 +- docs/metalctlv2_audit_list.md | 2 +- docs/metalctlv2_completion.md | 2 +- docs/metalctlv2_completion_bash.md | 2 +- docs/metalctlv2_completion_fish.md | 2 +- docs/metalctlv2_completion_powershell.md | 2 +- docs/metalctlv2_completion_zsh.md | 2 +- docs/metalctlv2_context.md | 2 +- docs/metalctlv2_context_add.md | 2 +- docs/metalctlv2_context_list.md | 2 +- docs/metalctlv2_context_remove.md | 2 +- docs/metalctlv2_context_set-project.md | 2 +- docs/metalctlv2_context_show-current.md | 2 +- docs/metalctlv2_context_switch.md | 2 +- docs/metalctlv2_context_update.md | 2 +- docs/metalctlv2_health.md | 2 +- docs/metalctlv2_image.md | 2 +- docs/metalctlv2_image_describe.md | 2 +- docs/metalctlv2_image_latest.md | 2 +- docs/metalctlv2_image_list.md | 2 +- docs/metalctlv2_ip.md | 2 +- docs/metalctlv2_ip_apply.md | 2 +- docs/metalctlv2_ip_create.md | 4 +- docs/metalctlv2_ip_delete.md | 2 +- docs/metalctlv2_ip_describe.md | 2 +- docs/metalctlv2_ip_edit.md | 2 +- docs/metalctlv2_ip_list.md | 2 +- docs/metalctlv2_ip_update.md | 45 +- docs/metalctlv2_login.md | 2 +- docs/metalctlv2_logout.md | 2 +- docs/metalctlv2_markdown.md | 2 +- docs/metalctlv2_project.md | 2 +- docs/metalctlv2_project_apply.md | 2 +- docs/metalctlv2_project_create.md | 2 +- docs/metalctlv2_project_delete.md | 2 +- docs/metalctlv2_project_describe.md | 2 +- docs/metalctlv2_project_edit.md | 2 +- docs/metalctlv2_project_invite.md | 2 +- docs/metalctlv2_project_invite_delete.md | 2 +- ...lv2_project_invite_generate-join-secret.md | 2 +- docs/metalctlv2_project_invite_list.md | 2 +- docs/metalctlv2_project_join.md | 2 +- docs/metalctlv2_project_list.md | 2 +- docs/metalctlv2_project_member.md | 2 +- docs/metalctlv2_project_member_delete.md | 2 +- docs/metalctlv2_project_member_list.md | 2 +- docs/metalctlv2_project_member_update.md | 2 +- docs/metalctlv2_project_update.md | 2 +- docs/metalctlv2_tenant.md | 2 +- docs/metalctlv2_tenant_apply.md | 2 +- docs/metalctlv2_tenant_create.md | 2 +- docs/metalctlv2_tenant_delete.md | 2 +- docs/metalctlv2_tenant_describe.md | 2 +- docs/metalctlv2_tenant_edit.md | 2 +- docs/metalctlv2_tenant_invite.md | 2 +- docs/metalctlv2_tenant_invite_delete.md | 2 +- ...tlv2_tenant_invite_generate-join-secret.md | 2 +- docs/metalctlv2_tenant_invite_list.md | 2 +- docs/metalctlv2_tenant_join.md | 2 +- docs/metalctlv2_tenant_list.md | 2 +- docs/metalctlv2_tenant_member.md | 2 +- docs/metalctlv2_tenant_member_list.md | 2 +- docs/metalctlv2_tenant_member_remove.md | 2 +- docs/metalctlv2_tenant_member_update.md | 2 +- docs/metalctlv2_tenant_update.md | 2 +- docs/metalctlv2_token.md | 2 +- docs/metalctlv2_token_apply.md | 2 +- docs/metalctlv2_token_create.md | 2 +- docs/metalctlv2_token_delete.md | 2 +- docs/metalctlv2_token_describe.md | 2 +- docs/metalctlv2_token_edit.md | 2 +- docs/metalctlv2_token_list.md | 2 +- docs/metalctlv2_token_update.md | 2 +- docs/metalctlv2_user.md | 2 +- docs/metalctlv2_user_describe.md | 2 +- docs/metalctlv2_version.md | 2 +- go.mod | 60 +- go.sum | 111 ++-- pkg/helpers/audit/audit.go | 4 +- tests/e2e/admin/audit_test.go | 111 ++++ tests/e2e/admin/component_test.go | 23 +- tests/e2e/admin/image_test.go | 218 +++++++ tests/e2e/admin/switch_test.go | 420 ++++++++++++-- tests/e2e/admin/task_test.go | 203 +++++++ tests/e2e/admin/token_test.go | 20 +- tests/e2e/api/audit_test.go | 163 ++++-- tests/e2e/api/image_test.go | 45 ++ tests/e2e/api/ip_test.go | 49 +- tests/e2e/api/project_test.go | 333 +++++++++++ tests/e2e/api/tenant_test.go | 548 ++++++++++++++++++ tests/e2e/api/token_test.go | 249 +++++++- tests/e2e/api/user_test.go | 50 ++ tests/e2e/api/version_test.go | 37 ++ tests/e2e/testresources/audit.go | 53 ++ tests/e2e/testresources/component.go | 47 ++ tests/e2e/testresources/images.go | 2 + tests/e2e/testresources/projects.go | 42 ++ tests/e2e/testresources/switch.go | 146 +++++ tests/e2e/testresources/tasks.go | 68 +++ tests/e2e/testresources/tenants.go | 44 ++ tests/e2e/testresources/tokens.go | 11 +- tests/e2e/testresources/user.go | 17 + tests/e2e/testresources/version.go | 14 + 123 files changed, 3413 insertions(+), 499 deletions(-) delete mode 100644 .github/release-drafter.yml delete mode 100644 .github/workflows/release-drafter.yaml create mode 100644 cmd/admin/v2/task.go create mode 100644 cmd/sorters/task.go create mode 100644 cmd/tableprinters/task.go create mode 100644 cmd/tableprinters/user.go create mode 100644 tests/e2e/admin/audit_test.go create mode 100644 tests/e2e/admin/image_test.go create mode 100644 tests/e2e/admin/task_test.go create mode 100644 tests/e2e/api/user_test.go create mode 100644 tests/e2e/api/version_test.go create mode 100644 tests/e2e/testresources/audit.go create mode 100644 tests/e2e/testresources/component.go create mode 100644 tests/e2e/testresources/switch.go create mode 100644 tests/e2e/testresources/tasks.go create mode 100644 tests/e2e/testresources/user.go create mode 100644 tests/e2e/testresources/version.go diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 59bc948..0000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1,30 +0,0 @@ -name-template: 'v$RESOLVED_VERSION' -tag-template: 'v$RESOLVED_VERSION' - -template: | - ## General Changes - - $CHANGES - -categories: -- title: '🚀 Features' - labels: - - 'feature' - - 'enhancement' -- title: '🐛 Bug Fixes' - labels: - - 'fix' - - 'bugfix' - - 'bug' - -version-resolver: - major: - labels: - - 'major' - minor: - labels: - - 'minor' - patch: - labels: - - 'patch' - default: patch diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c02ff18..0ad5063 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -16,27 +16,13 @@ env: IMAGE_NAME: ${{ github.repository }} jobs: - test: - runs-on: ubuntu-latest + draft: + uses: metal-stack/actions-common/.github/workflows/release-drafter.yaml@v1 - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - cache: false - - - name: Lint - uses: golangci/golangci-lint-action@v9 - with: - args: --build-tags integration --timeout=5m - - - name: Test - run: | - make test + go-build: + uses: metal-stack/actions-common/.github/workflows/go-build.yaml@v1 + with: + build: false build: runs-on: ubuntu-latest diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml deleted file mode 100644 index 44f017a..0000000 --- a/.github/workflows/release-drafter.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: Release Drafter Action - -on: - push: - branches: - - main - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: release-drafter/release-drafter@v6 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index c33a6be..043a985 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,11 @@ cli: .PHONY: test test: - CGO_ENABLED=1 go test ./... -race -coverprofile=coverage.out -covermode=atomic && go tool cover -func=coverage.out + CGO_ENABLED=1 go test ./... -race \ + -coverpkg=./... \ + -coverprofile=coverage.out \ + -covermode=atomic && \ + go tool cover -func=coverage.out .PHONY: golint golint: diff --git a/cmd/admin/v2/commands.go b/cmd/admin/v2/commands.go index 5bd0a65..70667cb 100644 --- a/cmd/admin/v2/commands.go +++ b/cmd/admin/v2/commands.go @@ -9,7 +9,7 @@ func AddCmds(cmd *cobra.Command, c *config.Config) { adminCmd := &cobra.Command{ Use: "admin", Short: "admin commands", - Long: "", + Long: "these commands utilize the admin api, which can only be accessed by metal-stack operators.", SilenceUsage: true, Hidden: true, } @@ -18,8 +18,8 @@ func AddCmds(cmd *cobra.Command, c *config.Config) { adminCmd.AddCommand(newComponentCmd(c)) adminCmd.AddCommand(newImageCmd(c)) adminCmd.AddCommand(newProjectCmd(c)) - adminCmd.AddCommand(newProjectCmd(c)) adminCmd.AddCommand(newSwitchCmd(c)) + adminCmd.AddCommand(newTaskCmd(c)) adminCmd.AddCommand(newTenantCmd(c)) adminCmd.AddCommand(newTokenCmd(c)) diff --git a/cmd/admin/v2/image.go b/cmd/admin/v2/image.go index 06cd556..4b5019d 100644 --- a/cmd/admin/v2/image.go +++ b/cmd/admin/v2/image.go @@ -40,6 +40,26 @@ func newImageCmd(c *config.Config) *cobra.Command { return gcli.DescribeAndPrint("", w.c.DescribePrinter) } }, + CreateCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("id", "", "image id") + cmd.Flags().String("url", "", "image url") + cmd.Flags().String("name", "", "image name") + cmd.Flags().String("classification", "", "image classification") + cmd.Flags().String("expires-in", "", "expires-in duration") + cmd.Flags().String("description", "", "image description") + cmd.Flags().StringSlice("features", nil, "image features can be machine and/or firewall") + }, + CreateRequestFromCLI: w.createFromCLI, + UpdateCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("id", "", "image id") + cmd.Flags().String("url", "", "image url") + cmd.Flags().String("name", "", "image name") + cmd.Flags().String("classification", "", "image classification") + cmd.Flags().String("expires-in", "", "expires-in duration") + cmd.Flags().String("description", "", "image description") + cmd.Flags().StringSlice("features", nil, "image features can be machine and/or firewall") + }, + UpdateRequestFromCLI: w.updateFromCLI, } return genericcli.NewCmds(cmdsConfig) @@ -63,30 +83,34 @@ func (c *image) Create(rq *adminv2.ImageServiceCreateRequest) (*apiv2.Image, err ctx, cancel := c.c.NewRequestContext() defer cancel() + resp, err := c.c.Client.Adminv2().Image().Create(ctx, rq) + if err != nil { + return nil, fmt.Errorf("failed to create image: %w", err) + } + + return resp.Image, nil +} + +func (c *image) createFromCLI() (*adminv2.ImageServiceCreateRequest, error) { var expiresAt *timestamppb.Timestamp if viper.IsSet("expires-in") { expiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in"))) } - req := &adminv2.ImageServiceCreateRequest{ + return &adminv2.ImageServiceCreateRequest{ Image: &apiv2.Image{ - Id: viper.GetString("id"), - Url: viper.GetString("url"), - Description: pointer.PointerOrNil(viper.GetString("description")), - ExpiresAt: expiresAt, - Features: imageFeaturesFromString(viper.GetStringSlice("features")), - Meta: &apiv2.Meta{ + Id: viper.GetString("id"), + Url: viper.GetString("url"), + Classification: imageClassificationFromString(viper.GetString("classification")), + Name: pointer.PointerOrNil(viper.GetString("name")), + Description: pointer.PointerOrNil(viper.GetString("description")), + ExpiresAt: expiresAt, + Features: imageFeaturesFromString(viper.GetStringSlice("features")), + Meta: &apiv2.Meta{ // TODO labels }, }, - } - - resp, err := c.c.Client.Adminv2().Image().Create(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to get image: %w", err) - } - - return resp.Image, nil + }, nil } func (c *image) Delete(id string) (*apiv2.Image, error) { @@ -139,29 +163,41 @@ func (c *image) Update(rq *adminv2.ImageServiceUpdateRequest) (*apiv2.Image, err ctx, cancel := c.c.NewRequestContext() defer cancel() - var expiresAt *timestamppb.Timestamp - if viper.IsSet("expires-in") { - expiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in"))) + resp, err := c.c.Client.Adminv2().Image().Update(ctx, rq) + if err != nil { + return nil, fmt.Errorf("failed to update image: %w", err) + } + + return resp.Image, nil +} + +func (c *image) updateFromCLI(args []string) (*adminv2.ImageServiceUpdateRequest, error) { + id, err := genericcli.GetExactlyOneArg(args) + if err != nil { + return nil, err } req := &adminv2.ImageServiceUpdateRequest{ - Id: viper.GetString("id"), - Url: new(viper.GetString("url")), + Id: id, + Url: pointer.PointerOrNil(viper.GetString("url")), + Name: pointer.PointerOrNil(viper.GetString("name")), Description: pointer.PointerOrNil(viper.GetString("description")), - ExpiresAt: expiresAt, - Features: imageFeaturesFromString(viper.GetStringSlice("features")), UpdateMeta: &apiv2.UpdateMeta{ - LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT, - UpdatedAt: rq.UpdateMeta.GetUpdatedAt(), + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_SERVER, }, } - resp, err := c.c.Client.Adminv2().Image().Update(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to get image: %w", err) + if viper.IsSet("expires-in") { + req.ExpiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in"))) + } + if viper.IsSet("features") { + req.Features = imageFeaturesFromString(viper.GetStringSlice("features")) + } + if viper.IsSet("classification") { + req.Classification = imageClassificationFromString(viper.GetString("classification")) } - return resp.Image, nil + return req, nil } func imageFeaturesFromString(features []string) []apiv2.ImageFeature { @@ -180,3 +216,16 @@ func imageFeaturesFromString(features []string) []apiv2.ImageFeature { } return result } + +func imageClassificationFromString(classification string) apiv2.ImageClassification { + switch strings.ToLower(strings.TrimSpace(classification)) { + case "preview": + return apiv2.ImageClassification_IMAGE_CLASSIFICATION_PREVIEW + case "supported": + return apiv2.ImageClassification_IMAGE_CLASSIFICATION_SUPPORTED + case "deprecated": + return apiv2.ImageClassification_IMAGE_CLASSIFICATION_DEPRECATED + } + + return apiv2.ImageClassification_IMAGE_CLASSIFICATION_UNSPECIFIED +} diff --git a/cmd/admin/v2/task.go b/cmd/admin/v2/task.go new file mode 100644 index 0000000..696491d --- /dev/null +++ b/cmd/admin/v2/task.go @@ -0,0 +1,125 @@ +package v2 + +import ( + "fmt" + + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/cli/cmd/config" + "github.com/metal-stack/cli/cmd/sorters" + "github.com/metal-stack/metal-lib/pkg/genericcli" + "github.com/metal-stack/metal-lib/pkg/genericcli/printers" + "github.com/metal-stack/metal-lib/pkg/pointer" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type task struct { + c *config.Config +} + +func newTaskCmd(c *config.Config) *cobra.Command { + w := &task{ + c: c, + } + + cmdsConfig := &genericcli.CmdsConfig[any, any, *adminv2.TaskInfo]{ + BinaryName: config.BinaryName, + GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.Fs), + Singular: "task", + Plural: "tasks", + Description: "get task insights", + DescribePrinter: func() printers.Printer { return c.DescribePrinter }, + ListPrinter: func() printers.Printer { return c.ListPrinter }, + Sorter: sorters.TaskSorter(), + DescribeCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("queue", "default", "the queue for which tasks should be described") + }, + ListCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("queue", "", "the queue for which tasks should be listed") + }, + DeleteCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("queue", "default", "the queue of the task which should be delete") + }, + OnlyCmds: genericcli.OnlyCmds(genericcli.ListCmd, genericcli.DescribeCmd, genericcli.DeleteCmd), + } + + queueCmd := &cobra.Command{ + Use: "queues", + Short: "list all queues", + RunE: func(cmd *cobra.Command, args []string) error { + return w.queues() + }, + } + + return genericcli.NewCmds(cmdsConfig, queueCmd) +} + +func (t *task) queues() error { + ctx, cancel := t.c.NewRequestContext() + defer cancel() + + req := &adminv2.TaskServiceQueuesRequest{} + + resp, err := t.c.Client.Adminv2().Task().Queues(ctx, req) + if err != nil { + return fmt.Errorf("failed to get task queues: %w", err) + } + + return t.c.ListPrinter.Print(resp) +} + +func (t *task) Get(id string) (*adminv2.TaskInfo, error) { + ctx, cancel := t.c.NewRequestContext() + defer cancel() + + req := &adminv2.TaskServiceGetRequest{TaskId: id, Queue: viper.GetString("queue")} + + resp, err := t.c.Client.Adminv2().Task().Get(ctx, req) + if err != nil { + return nil, fmt.Errorf("failed to get task: %w", err) + } + + return resp.Task, nil +} + +func (t *task) List() ([]*adminv2.TaskInfo, error) { + ctx, cancel := t.c.NewRequestContext() + defer cancel() + + req := &adminv2.TaskServiceListRequest{ + Queue: pointer.PointerOrNil(viper.GetString("queue")), + } + + resp, err := t.c.Client.Adminv2().Task().List(ctx, req) + if err != nil { + return nil, fmt.Errorf("failed to list tasks: %w", err) + } + + return resp.Tasks, nil +} + +func (t *task) Delete(id string) (*adminv2.TaskInfo, error) { + ctx, cancel := t.c.NewRequestContext() + defer cancel() + + req := &adminv2.TaskServiceDeleteRequest{TaskId: id, Queue: viper.GetString("queue")} + + _, err := t.c.Client.Adminv2().Task().Delete(ctx, req) + if err != nil { + return nil, fmt.Errorf("failed to delete task: %w", err) + } + + return nil, nil +} + +func (t *task) Create(rq any) (*adminv2.TaskInfo, error) { + panic("unimplemented") +} + +func (t *task) Convert(r *adminv2.TaskInfo) (string, any, any, error) { + panic("unimplemented") +} + +func (t *task) Update(rq any) (*adminv2.TaskInfo, error) { + panic("unimplemented") +} diff --git a/cmd/api/v2/ip.go b/cmd/api/v2/ip.go index dd9a45d..bcc8e40 100644 --- a/cmd/api/v2/ip.go +++ b/cmd/api/v2/ip.go @@ -1,8 +1,6 @@ package v2 import ( - "fmt" - apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/cli/cmd/config" "github.com/metal-stack/cli/cmd/sorters" @@ -42,7 +40,7 @@ func newIPCmd(c *config.Config) *cobra.Command { cmd.Flags().StringP("network", "n", "", "network from which the ip should get created") cmd.Flags().StringP("name", "", "", "name of the ip") cmd.Flags().StringP("description", "", "", "description of the ip") - cmd.Flags().StringSliceP("tags", "", nil, "tags to add to the ip") + cmd.Flags().StringSliceP("labels", "", nil, "labels to add to the ip") cmd.Flags().BoolP("static", "", false, "make this ip static") cmd.Flags().StringP("addressfamily", "", "", "addressfamily, can be either IPv4|IPv6, defaults to IPv4 (optional)") @@ -52,7 +50,8 @@ func newIPCmd(c *config.Config) *cobra.Command { cmd.Flags().StringP("project", "p", "", "project of the ip") cmd.Flags().String("name", "", "name of the ip") cmd.Flags().String("description", "", "description of the ip") - cmd.Flags().StringSlice("tags", nil, "tags of the ip") + cmd.Flags().StringArray("labels", nil, "adds (or edits) the volume labels in the form of =") + cmd.Flags().StringArray("remove-labels", nil, "removes the volume labels with the given key") cmd.Flags().Bool("static", false, "make this ip static") genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) @@ -67,17 +66,7 @@ func newIPCmd(c *config.Config) *cobra.Command { genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, - CreateRequestFromCLI: func() (*apiv2.IPServiceCreateRequest, error) { - return &apiv2.IPServiceCreateRequest{ - Project: c.GetProject(), - Network: viper.GetString("network"), - Name: pointer.PointerOrNil(viper.GetString("name")), - Description: pointer.PointerOrNil(viper.GetString("description")), - // Labels: viper.GetStringSlice("tags"), // FIXME implement - Type: new(ipStaticToType(viper.GetBool("static"))), - AddressFamily: addressFamilyToType(viper.GetString("addressfamily")), - }, nil - }, + CreateRequestFromCLI: w.createFromCLI, UpdateRequestFromCLI: w.updateFromCLI, ValidArgsFn: c.Completion.IpListCompletion, } @@ -85,39 +74,69 @@ func newIPCmd(c *config.Config) *cobra.Command { return genericcli.NewCmds(cmdsConfig) } +func (c *ip) createFromCLI() (*apiv2.IPServiceCreateRequest, error) { + var labels *apiv2.Labels = nil + + labelSlice := viper.GetStringSlice("labels") + if len(labelSlice) > 0 { + labelsMap, err := genericcli.LabelsToMap(labelSlice) + if err != nil { + return nil, err + } + labels = &apiv2.Labels{Labels: labelsMap} + } + return &apiv2.IPServiceCreateRequest{ + Project: c.c.GetProject(), + Network: viper.GetString("network"), + Name: pointer.PointerOrNil(viper.GetString("name")), + Description: pointer.PointerOrNil(viper.GetString("description")), + Labels: labels, + Type: new(ipStaticToType(viper.GetBool("static"))), + AddressFamily: addressFamilyToType(viper.GetString("addressfamily")), + }, nil +} + func (c *ip) updateFromCLI(args []string) (*apiv2.IPServiceUpdateRequest, error) { uuid, err := genericcli.GetExactlyOneArg(args) if err != nil { return nil, err } - ipToUpdate, err := c.Get(uuid) - if err != nil { - return nil, fmt.Errorf("unable to retrieve ip: %w", err) + req := &apiv2.IPServiceUpdateRequest{ + Ip: uuid, + Project: c.c.GetProject(), + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_SERVER, + }, } if viper.IsSet("name") { - ipToUpdate.Name = viper.GetString("name") + req.Name = pointer.PointerOrNil(viper.GetString("name")) } if viper.IsSet("description") { - ipToUpdate.Description = viper.GetString("description") + req.Description = pointer.PointerOrNil(viper.GetString("description")) } if viper.IsSet("static") { - ipToUpdate.Type = ipStaticToType(viper.GetBool("static")) + req.Type = pointer.PointerOrNil(ipStaticToType(viper.GetBool("static"))) + } + if viper.IsSet("remove-labels") || viper.IsSet("labels") { + labelsUpdate := &apiv2.UpdateLabels{} + + if viper.IsSet("remove-labels") { + labelsUpdate.Remove = viper.GetStringSlice("remove-labels") + } + + if viper.IsSet("labels") { + labels, err := genericcli.LabelsToMap(viper.GetStringSlice("labels")) + if err != nil { + return nil, err + } + labelsUpdate.Update = &apiv2.Labels{Labels: labels} + } + req.Labels = labelsUpdate } - // if viper.IsSet("tags") { - // if ipToUpdate.Meta == nil { - // ipToUpdate.Meta = &apiv2.Meta{ - // Labels: &apiv2.Labels{}, - // } - // } - // for _, l := - - // ipToUpdate.Meta.Labels = viper.GetStringSlice("tags") - // FIXME implement - // } - - return c.IpResponseToUpdate(ipToUpdate) + + return req, nil } func (c *ip) Create(rq *apiv2.IPServiceCreateRequest) (*apiv2.IP, error) { @@ -219,13 +238,13 @@ func IpResponseToCreate(r *apiv2.IP) *apiv2.IPServiceCreateRequest { } } -func (c *ip) IpResponseToUpdate(desired *apiv2.IP) (*apiv2.IPServiceUpdateRequest, error) { +func (c *ip) IpResponseToUpdate(r *apiv2.IP) (*apiv2.IPServiceUpdateRequest, error) { ctx, cancel := c.c.NewRequestContext() defer cancel() current, err := c.c.Client.Apiv2().IP().Get(ctx, &apiv2.IPServiceGetRequest{ - Ip: desired.Ip, - Project: desired.Project, + Ip: r.Ip, + Project: r.Project, }) if err != nil { return nil, err @@ -237,7 +256,7 @@ func (c *ip) IpResponseToUpdate(desired *apiv2.IP) (*apiv2.IPServiceUpdateReques } for key, currentValue := range current.Ip.Meta.Labels.Labels { - value, ok := desired.Meta.Labels.Labels[key] + value, ok := r.Meta.Labels.Labels[key] if !ok { updateLabels.Remove = append(updateLabels.Remove, key) @@ -253,12 +272,16 @@ func (c *ip) IpResponseToUpdate(desired *apiv2.IP) (*apiv2.IPServiceUpdateReques } return &apiv2.IPServiceUpdateRequest{ - Project: desired.Project, - Ip: desired.Ip, - Name: &desired.Name, - Description: &desired.Description, - Type: &desired.Type, + Project: r.Project, + Ip: r.Ip, + Name: &r.Name, + Description: &r.Description, + Type: &r.Type, Labels: updateLabels, + UpdateMeta: &apiv2.UpdateMeta{ + UpdatedAt: current.Ip.Meta.UpdatedAt, + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT, + }, }, nil } diff --git a/cmd/api/v2/project.go b/cmd/api/v2/project.go index cd9bc2f..25af7ab 100644 --- a/cmd/api/v2/project.go +++ b/cmd/api/v2/project.go @@ -8,6 +8,7 @@ import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/cli/cmd/config" "github.com/metal-stack/cli/cmd/sorters" + "github.com/metal-stack/cli/pkg/helpers" "github.com/metal-stack/metal-lib/pkg/genericcli" "github.com/metal-stack/metal-lib/pkg/genericcli/printers" "github.com/metal-stack/metal-lib/pkg/pointer" @@ -203,9 +204,12 @@ func (c *project) Create(rq *apiv2.ProjectServiceCreateRequest) (*apiv2.Project, resp, err := c.c.Client.Apiv2().Project().Create(ctx, rq) if err != nil { - return nil, fmt.Errorf("failed to create project: %w", err) - } + if helpers.IsAlreadyExists(err) { + return nil, genericcli.AlreadyExistsError() + } + return nil, err + } return resp.Project, nil } diff --git a/cmd/api/v2/tenant.go b/cmd/api/v2/tenant.go index 30ee3e1..b46dfba 100644 --- a/cmd/api/v2/tenant.go +++ b/cmd/api/v2/tenant.go @@ -8,6 +8,7 @@ import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/cli/cmd/config" "github.com/metal-stack/cli/cmd/sorters" + "github.com/metal-stack/cli/pkg/helpers" "github.com/metal-stack/metal-lib/pkg/genericcli" "github.com/metal-stack/metal-lib/pkg/genericcli/printers" "github.com/metal-stack/metal-lib/pkg/pointer" @@ -201,7 +202,11 @@ func (c *tenant) Create(rq *apiv2.TenantServiceCreateRequest) (*apiv2.Tenant, er resp, err := c.c.Client.Apiv2().Tenant().Create(ctx, rq) if err != nil { - return nil, fmt.Errorf("failed to create tenant: %w", err) + if helpers.IsAlreadyExists(err) { + return nil, genericcli.AlreadyExistsError() + } + + return nil, err } return resp.Tenant, nil @@ -230,10 +235,11 @@ func (c *tenant) Convert(r *apiv2.Tenant) (string, *apiv2.TenantServiceCreateReq AvatarUrl: &r.AvatarUrl, }, &apiv2.TenantServiceUpdateRequest{ - Login: r.Login, - Name: pointer.PointerOrNil(r.Name), - Email: pointer.PointerOrNil(r.Email), - AvatarUrl: pointer.PointerOrNil(r.AvatarUrl), + Login: r.Login, + Name: pointer.PointerOrNil(r.Name), + Email: pointer.PointerOrNil(r.Email), + Description: pointer.PointerOrNil(r.Description), + AvatarUrl: pointer.PointerOrNil(r.AvatarUrl), }, nil } diff --git a/cmd/login.go b/cmd/login.go index 02b1565..7e14376 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -128,7 +128,7 @@ func (l *login) login() error { } tokenResp, err := mc.Apiv2().Token().Create(context.Background(), &apiv2.TokenServiceCreateRequest{ - Description: "admin access issues by metal cli", + Description: "admin access issued by metal cli", Expires: durationpb.New(3 * time.Hour), AdminRole: new(apiv2.AdminRole((apiv2.AdminRole_value[viper.GetString("admin-role")]))), }) diff --git a/cmd/sorters/task.go b/cmd/sorters/task.go new file mode 100644 index 0000000..4a15a47 --- /dev/null +++ b/cmd/sorters/task.go @@ -0,0 +1,35 @@ +package sorters + +import ( + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/metal-lib/pkg/multisort" +) + +func TaskSorter() *multisort.Sorter[*adminv2.TaskInfo] { + return multisort.New(multisort.FieldMap[*adminv2.TaskInfo]{ + "id": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.Id, b.Id, descending) + }, + "queue": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.Queue, b.Queue, descending) + }, + "type": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.Type, b.Type, descending) + }, + "state": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(adminv2.TaskState_name[int32(a.State)], adminv2.TaskState_name[int32(b.State)], descending) + }, + "retried": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.Retried, b.Retried, descending) + }, + "completed-at": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.CompletedAt.AsTime().UnixMilli(), b.CompletedAt.AsTime().UnixMilli(), descending) + }, + "last-failed-at": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.LastFailedAt.AsTime().UnixMilli(), b.LastFailedAt.AsTime().UnixMilli(), descending) + }, + "deadline-at": func(a, b *adminv2.TaskInfo, descending bool) multisort.CompareResult { + return multisort.Compare(a.Deadline.AsTime().UnixMilli(), b.Deadline.AsTime().UnixMilli(), descending) + }, + }, multisort.Keys{{ID: "id"}}) +} diff --git a/cmd/tableprinters/common.go b/cmd/tableprinters/common.go index 317eeb8..933e6f9 100644 --- a/cmd/tableprinters/common.go +++ b/cmd/tableprinters/common.go @@ -83,6 +83,13 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin case []*apiv2.ProjectMember: return t.ProjectMemberTable(d, wide) + case *adminv2.TaskInfo: + return t.TaskTable(pointer.WrapInSlice(d), wide) + case []*adminv2.TaskInfo: + return t.TaskTable(d, wide) + case *adminv2.TaskServiceQueuesResponse: + return t.TaskQueueTable(d, wide) + case *apiv2.Token: return t.TokenTable(pointer.WrapInSlice(d), wide) case []*apiv2.Token: @@ -113,6 +120,11 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin case *adminv2.SwitchServiceConnectedMachinesResponse: return t.SwitchWithConnectedMachinesTable(d.SwitchesWithMachines, wide) + case *apiv2.User: + return t.UserTable(pointer.WrapInSlice(d), wide) + case []*apiv2.User: + return t.UserTable(d, wide) + default: return nil, nil, fmt.Errorf("unknown table printer for type: %T", d) } diff --git a/cmd/tableprinters/switch.go b/cmd/tableprinters/switch.go index 17e5945..f898caa 100644 --- a/cmd/tableprinters/switch.go +++ b/cmd/tableprinters/switch.go @@ -336,7 +336,7 @@ func (t *TablePrinter) getMachineStatusEmojis(m *apiv2.Machine) string { switch status.Condition.State { case apiv2.MachineState_MACHINE_STATE_LOCKED: emojis = append(emojis, lock) - case apiv2.MachineState_MACHINE_STATE_RESERVED: + case apiv2.MachineState_MACHINE_STATE_TAINTED: emojis = append(emojis, bark) default: // noop diff --git a/cmd/tableprinters/switch_test.go b/cmd/tableprinters/switch_test.go index 7fdb716..138b782 100644 --- a/cmd/tableprinters/switch_test.go +++ b/cmd/tableprinters/switch_test.go @@ -703,7 +703,7 @@ func TestTablePrinter_SwitchWithConnectedMachinesTable(t *testing.T) { }, Status: &apiv2.MachineStatus{ Condition: &apiv2.MachineCondition{ - State: apiv2.MachineState_MACHINE_STATE_RESERVED, + State: apiv2.MachineState_MACHINE_STATE_TAINTED, }, Liveliness: apiv2.MachineLiveliness_MACHINE_LIVELINESS_UNKNOWN, }, diff --git a/cmd/tableprinters/task.go b/cmd/tableprinters/task.go new file mode 100644 index 0000000..34ea6d9 --- /dev/null +++ b/cmd/tableprinters/task.go @@ -0,0 +1,74 @@ +package tableprinters + +import ( + "time" + + "github.com/google/uuid" + "github.com/metal-stack/api/go/enum" + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/metal-lib/pkg/genericcli" +) + +func (t *TablePrinter) TaskTable(data []*adminv2.TaskInfo, wide bool) ([]string, [][]string, error) { + var ( + rows [][]string + ) + + header := []string{"ID", "Queue", "When", "Type", "State"} + + if wide { + header = []string{"ID", "Queue", "When", "Type", "State", "Issued At", "Payload", "Result"} + } + + for _, task := range data { + var ( + id = task.Id + queue = task.Queue + typeString = task.Type + payload = genericcli.TruncateEnd(string(task.Payload), 40) + result = genericcli.TruncateEnd(string(task.Result), 40) + ) + + state, err := enum.GetStringValue(task.State) + if err != nil { + state = new("unknown") + } + + parsed, err := uuid.Parse(id) + if err != nil { + return nil, nil, err + } + + var ( + sec, nano = parsed.Time().UnixTime() + issuedAt = time.Unix(sec, nano).UTC() + when = humanizeDuration(time.Since(issuedAt)) + " ago" + ) + + if wide { + rows = append(rows, []string{id, queue, when, typeString, *state, issuedAt.String(), payload, result}) + } else { + rows = append(rows, []string{id, queue, when, typeString, *state}) + } + } + + t.t.DisableAutoWrap(false) + + return header, rows, nil +} + +func (t *TablePrinter) TaskQueueTable(data *adminv2.TaskServiceQueuesResponse, _ bool) ([]string, [][]string, error) { + var ( + rows [][]string + ) + + header := []string{"Queue"} + + for _, queue := range data.Queues { + rows = append(rows, []string{queue}) + } + + t.t.DisableAutoWrap(false) + + return header, rows, nil +} diff --git a/cmd/tableprinters/user.go b/cmd/tableprinters/user.go new file mode 100644 index 0000000..c649e17 --- /dev/null +++ b/cmd/tableprinters/user.go @@ -0,0 +1,50 @@ +package tableprinters + +import ( + "strings" + + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" +) + +type Named interface { + GetName() string +} + +func (t *TablePrinter) UserTable(data []*apiv2.User, wide bool) ([]string, [][]string, error) { + var ( + rows [][]string + header = []string{"Login", "Name", "Email"} + ) + + if wide { + header = []string{"Login", "Name", "Email", "Tenants", "Projects"} + } + + for _, user := range data { + login := user.Login + name := user.Name + email := user.Email + + if wide { + rows = append(rows, []string{login, name, email, namesString(user.Tenants), namesString(user.Projects)}) + + } else { + rows = append(rows, []string{login, name, email}) + } + } + + return header, rows, nil +} + +func namesString[T Named](arr []T) string { + names := make([]string, 0, len(arr)) + + for _, t := range arr { + name := t.GetName() + if name != "" { + names = append(names, name) + } + } + + return strings.Join(names, ", ") +} diff --git a/docs/metalctlv2.md b/docs/metalctlv2.md index 378c0ce..1187792 100644 --- a/docs/metalctlv2.md +++ b/docs/metalctlv2.md @@ -11,7 +11,7 @@ cli for managing entities in metal-stack --debug debug output --force-color force colored output even without tty -h, --help help for metalctlv2 - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_api-methods.md b/docs/metalctlv2_api-methods.md index 11de69a..960ef02 100644 --- a/docs/metalctlv2_api-methods.md +++ b/docs/metalctlv2_api-methods.md @@ -21,7 +21,7 @@ metalctlv2 api-methods [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_audit.md b/docs/metalctlv2_audit.md index 095ab64..ed95dd1 100644 --- a/docs/metalctlv2_audit.md +++ b/docs/metalctlv2_audit.md @@ -20,7 +20,7 @@ read api audit traces of a tenant -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_audit_describe.md b/docs/metalctlv2_audit_describe.md index 23e1905..cc382a5 100644 --- a/docs/metalctlv2_audit_describe.md +++ b/docs/metalctlv2_audit_describe.md @@ -23,7 +23,7 @@ metalctlv2 audit describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_audit_list.md b/docs/metalctlv2_audit_list.md index 3506d75..79189f7 100644 --- a/docs/metalctlv2_audit_list.md +++ b/docs/metalctlv2_audit_list.md @@ -34,7 +34,7 @@ metalctlv2 audit list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_completion.md b/docs/metalctlv2_completion.md index 5b5f52f..773da84 100644 --- a/docs/metalctlv2_completion.md +++ b/docs/metalctlv2_completion.md @@ -22,7 +22,7 @@ See each sub-command's help for details on how to use the generated script. -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_completion_bash.md b/docs/metalctlv2_completion_bash.md index 6b43f93..38a1ede 100644 --- a/docs/metalctlv2_completion_bash.md +++ b/docs/metalctlv2_completion_bash.md @@ -45,7 +45,7 @@ metalctlv2 completion bash -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_completion_fish.md b/docs/metalctlv2_completion_fish.md index 14547e6..69657e7 100644 --- a/docs/metalctlv2_completion_fish.md +++ b/docs/metalctlv2_completion_fish.md @@ -36,7 +36,7 @@ metalctlv2 completion fish [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_completion_powershell.md b/docs/metalctlv2_completion_powershell.md index bc60343..6b9c650 100644 --- a/docs/metalctlv2_completion_powershell.md +++ b/docs/metalctlv2_completion_powershell.md @@ -33,7 +33,7 @@ metalctlv2 completion powershell [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_completion_zsh.md b/docs/metalctlv2_completion_zsh.md index 4d9a9eb..9ba9e8e 100644 --- a/docs/metalctlv2_completion_zsh.md +++ b/docs/metalctlv2_completion_zsh.md @@ -47,7 +47,7 @@ metalctlv2 completion zsh [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context.md b/docs/metalctlv2_context.md index b07774e..0f0e0b1 100644 --- a/docs/metalctlv2_context.md +++ b/docs/metalctlv2_context.md @@ -24,7 +24,7 @@ metalctlv2 context [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_add.md b/docs/metalctlv2_context_add.md index d60a35c..68ff412 100644 --- a/docs/metalctlv2_context_add.md +++ b/docs/metalctlv2_context_add.md @@ -24,7 +24,7 @@ metalctlv2 context add [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. ``` diff --git a/docs/metalctlv2_context_list.md b/docs/metalctlv2_context_list.md index a3f6421..6033cd2 100644 --- a/docs/metalctlv2_context_list.md +++ b/docs/metalctlv2_context_list.md @@ -20,7 +20,7 @@ metalctlv2 context list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_remove.md b/docs/metalctlv2_context_remove.md index 61118c7..478c662 100644 --- a/docs/metalctlv2_context_remove.md +++ b/docs/metalctlv2_context_remove.md @@ -20,7 +20,7 @@ metalctlv2 context remove [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_set-project.md b/docs/metalctlv2_context_set-project.md index 98a9fa5..b3a18a2 100644 --- a/docs/metalctlv2_context_set-project.md +++ b/docs/metalctlv2_context_set-project.md @@ -20,7 +20,7 @@ metalctlv2 context set-project [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_show-current.md b/docs/metalctlv2_context_show-current.md index cd27cd9..6146f5b 100644 --- a/docs/metalctlv2_context_show-current.md +++ b/docs/metalctlv2_context_show-current.md @@ -20,7 +20,7 @@ metalctlv2 context show-current [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_switch.md b/docs/metalctlv2_context_switch.md index 09177e5..0eb28a8 100644 --- a/docs/metalctlv2_context_switch.md +++ b/docs/metalctlv2_context_switch.md @@ -24,7 +24,7 @@ metalctlv2 context switch [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_context_update.md b/docs/metalctlv2_context_update.md index 0908bd5..393da6d 100644 --- a/docs/metalctlv2_context_update.md +++ b/docs/metalctlv2_context_update.md @@ -24,7 +24,7 @@ metalctlv2 context update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. ``` diff --git a/docs/metalctlv2_health.md b/docs/metalctlv2_health.md index 99a96b4..4e607ee 100644 --- a/docs/metalctlv2_health.md +++ b/docs/metalctlv2_health.md @@ -24,7 +24,7 @@ metalctlv2 health [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_image.md b/docs/metalctlv2_image.md index e55d75d..7f1e495 100644 --- a/docs/metalctlv2_image.md +++ b/docs/metalctlv2_image.md @@ -20,7 +20,7 @@ manage images which are used to be installed on machines and firewalls -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_image_describe.md b/docs/metalctlv2_image_describe.md index ae89061..aed8321 100644 --- a/docs/metalctlv2_image_describe.md +++ b/docs/metalctlv2_image_describe.md @@ -20,7 +20,7 @@ metalctlv2 image describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_image_latest.md b/docs/metalctlv2_image_latest.md index 9a12e52..73d363f 100644 --- a/docs/metalctlv2_image_latest.md +++ b/docs/metalctlv2_image_latest.md @@ -21,7 +21,7 @@ metalctlv2 image latest [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_image_list.md b/docs/metalctlv2_image_list.md index 36af421..b1764ab 100644 --- a/docs/metalctlv2_image_list.md +++ b/docs/metalctlv2_image_list.md @@ -26,7 +26,7 @@ metalctlv2 image list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip.md b/docs/metalctlv2_ip.md index 401c938..afd5d6f 100644 --- a/docs/metalctlv2_ip.md +++ b/docs/metalctlv2_ip.md @@ -20,7 +20,7 @@ an ip address of metal-stack.io -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_apply.md b/docs/metalctlv2_ip_apply.md index 088a6d8..91652d5 100644 --- a/docs/metalctlv2_ip_apply.md +++ b/docs/metalctlv2_ip_apply.md @@ -35,7 +35,7 @@ metalctlv2 ip apply [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_create.md b/docs/metalctlv2_ip_create.md index 5055893..0e493c3 100644 --- a/docs/metalctlv2_ip_create.md +++ b/docs/metalctlv2_ip_create.md @@ -25,12 +25,12 @@ metalctlv2 ip create [flags] the file can also contain multiple documents and perform a bulk operation. -h, --help help for create + --labels strings labels to add to the ip --name string name of the ip -n, --network string network from which the ip should get created -p, --project string project of the ip --skip-security-prompts skips security prompt for bulk operations --static make this ip static - --tags strings tags to add to the ip --timestamps when used with --file (bulk operation): prints timestamps in-between the operations ``` @@ -42,7 +42,7 @@ metalctlv2 ip create [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_delete.md b/docs/metalctlv2_ip_delete.md index 61d0290..1e113d3 100644 --- a/docs/metalctlv2_ip_delete.md +++ b/docs/metalctlv2_ip_delete.md @@ -36,7 +36,7 @@ metalctlv2 ip delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_describe.md b/docs/metalctlv2_ip_describe.md index aae77b5..b206813 100644 --- a/docs/metalctlv2_ip_describe.md +++ b/docs/metalctlv2_ip_describe.md @@ -21,7 +21,7 @@ metalctlv2 ip describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_edit.md b/docs/metalctlv2_ip_edit.md index a9a9622..e362f7e 100644 --- a/docs/metalctlv2_ip_edit.md +++ b/docs/metalctlv2_ip_edit.md @@ -20,7 +20,7 @@ metalctlv2 ip edit [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_list.md b/docs/metalctlv2_ip_list.md index 37cde45..1ac5a43 100644 --- a/docs/metalctlv2_ip_list.md +++ b/docs/metalctlv2_ip_list.md @@ -22,7 +22,7 @@ metalctlv2 ip list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_ip_update.md b/docs/metalctlv2_ip_update.md index db9ca66..e3d0d1f 100644 --- a/docs/metalctlv2_ip_update.md +++ b/docs/metalctlv2_ip_update.md @@ -9,27 +9,28 @@ metalctlv2 ip update [flags] ### Options ``` - --bulk-output when used with --file (bulk operation): prints results at the end as a list. default is printing results intermediately during the operation, which causes single entities to be printed in a row. - --description string description of the ip - -f, --file string filename of the create or update request in yaml format, or - for stdin. - - Example: - $ metalctlv2 ip describe ip-1 -o yaml > ip.yaml - $ vi ip.yaml - $ # either via stdin - $ cat ip.yaml | metalctlv2 ip update -f - - $ # or via file - $ metalctlv2 ip update -f ip.yaml - - the file can also contain multiple documents and perform a bulk operation. - - -h, --help help for update - --name string name of the ip - -p, --project string project of the ip - --skip-security-prompts skips security prompt for bulk operations - --static make this ip static - --tags strings tags of the ip - --timestamps when used with --file (bulk operation): prints timestamps in-between the operations + --bulk-output when used with --file (bulk operation): prints results at the end as a list. default is printing results intermediately during the operation, which causes single entities to be printed in a row. + --description string description of the ip + -f, --file string filename of the create or update request in yaml format, or - for stdin. + + Example: + $ metalctlv2 ip describe ip-1 -o yaml > ip.yaml + $ vi ip.yaml + $ # either via stdin + $ cat ip.yaml | metalctlv2 ip update -f - + $ # or via file + $ metalctlv2 ip update -f ip.yaml + + the file can also contain multiple documents and perform a bulk operation. + + -h, --help help for update + --labels stringArray adds (or edits) the volume labels in the form of = + --name string name of the ip + -p, --project string project of the ip + --remove-labels stringArray removes the volume labels with the given key + --skip-security-prompts skips security prompt for bulk operations + --static make this ip static + --timestamps when used with --file (bulk operation): prints timestamps in-between the operations ``` ### Options inherited from parent commands @@ -40,7 +41,7 @@ metalctlv2 ip update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_login.md b/docs/metalctlv2_login.md index 28e50a8..e961c52 100644 --- a/docs/metalctlv2_login.md +++ b/docs/metalctlv2_login.md @@ -22,7 +22,7 @@ metalctlv2 login [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_logout.md b/docs/metalctlv2_logout.md index bc7f032..560a2a4 100644 --- a/docs/metalctlv2_logout.md +++ b/docs/metalctlv2_logout.md @@ -22,7 +22,7 @@ metalctlv2 logout [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_markdown.md b/docs/metalctlv2_markdown.md index cd98b36..c298007 100644 --- a/docs/metalctlv2_markdown.md +++ b/docs/metalctlv2_markdown.md @@ -20,7 +20,7 @@ metalctlv2 markdown [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project.md b/docs/metalctlv2_project.md index 164d3d2..f356a7e 100644 --- a/docs/metalctlv2_project.md +++ b/docs/metalctlv2_project.md @@ -20,7 +20,7 @@ manage api projects -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_apply.md b/docs/metalctlv2_project_apply.md index a5b3eb5..1afdee1 100644 --- a/docs/metalctlv2_project_apply.md +++ b/docs/metalctlv2_project_apply.md @@ -35,7 +35,7 @@ metalctlv2 project apply [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_create.md b/docs/metalctlv2_project_create.md index 09322ed..f7e7df1 100644 --- a/docs/metalctlv2_project_create.md +++ b/docs/metalctlv2_project_create.md @@ -38,7 +38,7 @@ metalctlv2 project create [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_delete.md b/docs/metalctlv2_project_delete.md index 2df90b6..bd68477 100644 --- a/docs/metalctlv2_project_delete.md +++ b/docs/metalctlv2_project_delete.md @@ -35,7 +35,7 @@ metalctlv2 project delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_describe.md b/docs/metalctlv2_project_describe.md index 1173530..14a5ecc 100644 --- a/docs/metalctlv2_project_describe.md +++ b/docs/metalctlv2_project_describe.md @@ -20,7 +20,7 @@ metalctlv2 project describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_edit.md b/docs/metalctlv2_project_edit.md index 33f4d77..eaa80eb 100644 --- a/docs/metalctlv2_project_edit.md +++ b/docs/metalctlv2_project_edit.md @@ -20,7 +20,7 @@ metalctlv2 project edit [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_invite.md b/docs/metalctlv2_project_invite.md index 9610fbf..bfcce95 100644 --- a/docs/metalctlv2_project_invite.md +++ b/docs/metalctlv2_project_invite.md @@ -16,7 +16,7 @@ manage project invites -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_invite_delete.md b/docs/metalctlv2_project_invite_delete.md index 48e643d..963bcf4 100644 --- a/docs/metalctlv2_project_invite_delete.md +++ b/docs/metalctlv2_project_invite_delete.md @@ -21,7 +21,7 @@ metalctlv2 project invite delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_invite_generate-join-secret.md b/docs/metalctlv2_project_invite_generate-join-secret.md index 273cb5c..4fb7432 100644 --- a/docs/metalctlv2_project_invite_generate-join-secret.md +++ b/docs/metalctlv2_project_invite_generate-join-secret.md @@ -22,7 +22,7 @@ metalctlv2 project invite generate-join-secret [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_invite_list.md b/docs/metalctlv2_project_invite_list.md index 80dfd85..a319ffc 100644 --- a/docs/metalctlv2_project_invite_list.md +++ b/docs/metalctlv2_project_invite_list.md @@ -22,7 +22,7 @@ metalctlv2 project invite list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_join.md b/docs/metalctlv2_project_join.md index fdf2be0..945f19f 100644 --- a/docs/metalctlv2_project_join.md +++ b/docs/metalctlv2_project_join.md @@ -20,7 +20,7 @@ metalctlv2 project join [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_list.md b/docs/metalctlv2_project_list.md index edbba1a..8c956df 100644 --- a/docs/metalctlv2_project_list.md +++ b/docs/metalctlv2_project_list.md @@ -23,7 +23,7 @@ metalctlv2 project list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_member.md b/docs/metalctlv2_project_member.md index 4e5d082..5a3497d 100644 --- a/docs/metalctlv2_project_member.md +++ b/docs/metalctlv2_project_member.md @@ -16,7 +16,7 @@ manage project members -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_member_delete.md b/docs/metalctlv2_project_member_delete.md index 962cd54..b45509b 100644 --- a/docs/metalctlv2_project_member_delete.md +++ b/docs/metalctlv2_project_member_delete.md @@ -21,7 +21,7 @@ metalctlv2 project member delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_member_list.md b/docs/metalctlv2_project_member_list.md index d05e2a7..5527476 100644 --- a/docs/metalctlv2_project_member_list.md +++ b/docs/metalctlv2_project_member_list.md @@ -22,7 +22,7 @@ metalctlv2 project member list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_member_update.md b/docs/metalctlv2_project_member_update.md index 384f9b1..388d5ea 100644 --- a/docs/metalctlv2_project_member_update.md +++ b/docs/metalctlv2_project_member_update.md @@ -22,7 +22,7 @@ metalctlv2 project member update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_project_update.md b/docs/metalctlv2_project_update.md index 87ec7d5..979c4ff 100644 --- a/docs/metalctlv2_project_update.md +++ b/docs/metalctlv2_project_update.md @@ -37,7 +37,7 @@ metalctlv2 project update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant.md b/docs/metalctlv2_tenant.md index 0007e09..6f76844 100644 --- a/docs/metalctlv2_tenant.md +++ b/docs/metalctlv2_tenant.md @@ -20,7 +20,7 @@ manage api tenants -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_apply.md b/docs/metalctlv2_tenant_apply.md index 50670e4..8a6d93f 100644 --- a/docs/metalctlv2_tenant_apply.md +++ b/docs/metalctlv2_tenant_apply.md @@ -35,7 +35,7 @@ metalctlv2 tenant apply [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_create.md b/docs/metalctlv2_tenant_create.md index 86f7da7..42fd2aa 100644 --- a/docs/metalctlv2_tenant_create.md +++ b/docs/metalctlv2_tenant_create.md @@ -39,7 +39,7 @@ metalctlv2 tenant create [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_delete.md b/docs/metalctlv2_tenant_delete.md index 5a80b42..38ee3c2 100644 --- a/docs/metalctlv2_tenant_delete.md +++ b/docs/metalctlv2_tenant_delete.md @@ -35,7 +35,7 @@ metalctlv2 tenant delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_describe.md b/docs/metalctlv2_tenant_describe.md index 5879c6d..7fb3c1c 100644 --- a/docs/metalctlv2_tenant_describe.md +++ b/docs/metalctlv2_tenant_describe.md @@ -20,7 +20,7 @@ metalctlv2 tenant describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_edit.md b/docs/metalctlv2_tenant_edit.md index 483c901..466da36 100644 --- a/docs/metalctlv2_tenant_edit.md +++ b/docs/metalctlv2_tenant_edit.md @@ -20,7 +20,7 @@ metalctlv2 tenant edit [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_invite.md b/docs/metalctlv2_tenant_invite.md index 16bea96..658268b 100644 --- a/docs/metalctlv2_tenant_invite.md +++ b/docs/metalctlv2_tenant_invite.md @@ -16,7 +16,7 @@ manage tenant invites -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_invite_delete.md b/docs/metalctlv2_tenant_invite_delete.md index 10c8b20..e1d1b3c 100644 --- a/docs/metalctlv2_tenant_invite_delete.md +++ b/docs/metalctlv2_tenant_invite_delete.md @@ -21,7 +21,7 @@ metalctlv2 tenant invite delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_invite_generate-join-secret.md b/docs/metalctlv2_tenant_invite_generate-join-secret.md index cf49ccc..be22cef 100644 --- a/docs/metalctlv2_tenant_invite_generate-join-secret.md +++ b/docs/metalctlv2_tenant_invite_generate-join-secret.md @@ -22,7 +22,7 @@ metalctlv2 tenant invite generate-join-secret [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_invite_list.md b/docs/metalctlv2_tenant_invite_list.md index 72cb672..01b2cfa 100644 --- a/docs/metalctlv2_tenant_invite_list.md +++ b/docs/metalctlv2_tenant_invite_list.md @@ -22,7 +22,7 @@ metalctlv2 tenant invite list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_join.md b/docs/metalctlv2_tenant_join.md index 8f57bc9..fb48fe1 100644 --- a/docs/metalctlv2_tenant_join.md +++ b/docs/metalctlv2_tenant_join.md @@ -20,7 +20,7 @@ metalctlv2 tenant join [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_list.md b/docs/metalctlv2_tenant_list.md index 863ec6e..ee7dae1 100644 --- a/docs/metalctlv2_tenant_list.md +++ b/docs/metalctlv2_tenant_list.md @@ -23,7 +23,7 @@ metalctlv2 tenant list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_member.md b/docs/metalctlv2_tenant_member.md index ebb53c4..8d119dc 100644 --- a/docs/metalctlv2_tenant_member.md +++ b/docs/metalctlv2_tenant_member.md @@ -16,7 +16,7 @@ manage tenant members -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_member_list.md b/docs/metalctlv2_tenant_member_list.md index 1aff48c..b97fa91 100644 --- a/docs/metalctlv2_tenant_member_list.md +++ b/docs/metalctlv2_tenant_member_list.md @@ -22,7 +22,7 @@ metalctlv2 tenant member list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_member_remove.md b/docs/metalctlv2_tenant_member_remove.md index 5b2ceb5..830f05b 100644 --- a/docs/metalctlv2_tenant_member_remove.md +++ b/docs/metalctlv2_tenant_member_remove.md @@ -21,7 +21,7 @@ metalctlv2 tenant member remove [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_member_update.md b/docs/metalctlv2_tenant_member_update.md index 3f66a9a..cf93cb7 100644 --- a/docs/metalctlv2_tenant_member_update.md +++ b/docs/metalctlv2_tenant_member_update.md @@ -22,7 +22,7 @@ metalctlv2 tenant member update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_tenant_update.md b/docs/metalctlv2_tenant_update.md index 768a568..433fb06 100644 --- a/docs/metalctlv2_tenant_update.md +++ b/docs/metalctlv2_tenant_update.md @@ -37,7 +37,7 @@ metalctlv2 tenant update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token.md b/docs/metalctlv2_token.md index 01394f8..82cbe42 100644 --- a/docs/metalctlv2_token.md +++ b/docs/metalctlv2_token.md @@ -20,7 +20,7 @@ manage api tokens for accessing the metal-stack.io api -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_apply.md b/docs/metalctlv2_token_apply.md index d622e45..72b2fee 100644 --- a/docs/metalctlv2_token_apply.md +++ b/docs/metalctlv2_token_apply.md @@ -35,7 +35,7 @@ metalctlv2 token apply [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_create.md b/docs/metalctlv2_token_create.md index f9f33d1..f2bb26a 100644 --- a/docs/metalctlv2_token_create.md +++ b/docs/metalctlv2_token_create.md @@ -41,7 +41,7 @@ metalctlv2 token create [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_delete.md b/docs/metalctlv2_token_delete.md index 6e72e28..6155756 100644 --- a/docs/metalctlv2_token_delete.md +++ b/docs/metalctlv2_token_delete.md @@ -35,7 +35,7 @@ metalctlv2 token delete [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_describe.md b/docs/metalctlv2_token_describe.md index 2997b43..016694f 100644 --- a/docs/metalctlv2_token_describe.md +++ b/docs/metalctlv2_token_describe.md @@ -20,7 +20,7 @@ metalctlv2 token describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_edit.md b/docs/metalctlv2_token_edit.md index 051ef01..77abfb8 100644 --- a/docs/metalctlv2_token_edit.md +++ b/docs/metalctlv2_token_edit.md @@ -20,7 +20,7 @@ metalctlv2 token edit [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_list.md b/docs/metalctlv2_token_list.md index 64935de..6cdd69a 100644 --- a/docs/metalctlv2_token_list.md +++ b/docs/metalctlv2_token_list.md @@ -21,7 +21,7 @@ metalctlv2 token list [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_token_update.md b/docs/metalctlv2_token_update.md index 24545a6..4055f11 100644 --- a/docs/metalctlv2_token_update.md +++ b/docs/metalctlv2_token_update.md @@ -35,7 +35,7 @@ metalctlv2 token update [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_user.md b/docs/metalctlv2_user.md index 50677ce..c416e39 100644 --- a/docs/metalctlv2_user.md +++ b/docs/metalctlv2_user.md @@ -20,7 +20,7 @@ manage api users for accessing the metal-stack.io api -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_user_describe.md b/docs/metalctlv2_user_describe.md index ddcbafa..9d994bd 100644 --- a/docs/metalctlv2_user_describe.md +++ b/docs/metalctlv2_user_describe.md @@ -20,7 +20,7 @@ metalctlv2 user describe [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/docs/metalctlv2_version.md b/docs/metalctlv2_version.md index 8f98db6..40350c6 100644 --- a/docs/metalctlv2_version.md +++ b/docs/metalctlv2_version.md @@ -24,7 +24,7 @@ metalctlv2 version [flags] -c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml) --debug debug output --force-color force colored output even without tty - -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact (for apply, create, update, delete commands from file the raw output formatters must be used). (default "table") --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. --timeout duration request timeout used for api requests ``` diff --git a/go.mod b/go.mod index 9de5756..28b8d0b 100644 --- a/go.mod +++ b/go.mod @@ -3,56 +3,75 @@ module github.com/metal-stack/cli go 1.26 require ( +<<<<<<< HEAD connectrpc.com/connect v1.19.1 +======= + buf.build/go/protoyaml v0.7.0 + connectrpc.com/connect v1.20.0 +>>>>>>> main connectrpc.com/validate v0.6.0 github.com/dustin/go-humanize v1.0.1 - github.com/fatih/color v1.18.0 + github.com/fatih/color v1.19.0 github.com/google/go-cmp v0.7.0 +<<<<<<< HEAD github.com/metal-stack/api v0.0.58 github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f +======= + github.com/google/uuid v1.6.0 + github.com/metal-stack/api v0.1.0 + github.com/metal-stack/metal-lib v0.25.1 +>>>>>>> main github.com/metal-stack/v v1.0.3 github.com/spf13/afero v1.15.0 github.com/spf13/cobra v1.10.2 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 +<<<<<<< HEAD google.golang.org/grpc v1.79.3 +======= + google.golang.org/grpc v1.81.1 +>>>>>>> main google.golang.org/protobuf v1.36.11 sigs.k8s.io/yaml v1.6.0 ) require ( +<<<<<<< HEAD buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect buf.build/go/protovalidate v1.1.3 // indirect buf.build/go/protoyaml v0.6.0 // indirect cel.dev/expr v0.25.1 // indirect +======= + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect + buf.build/go/protovalidate v1.2.0 // indirect + cel.dev/expr v0.25.2 // indirect +>>>>>>> main github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/clipperhouse/displaywidth v0.6.2 // indirect - github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/clipperhouse/displaywidth v0.10.0 // indirect + github.com/clipperhouse/uax29/v2 v2.6.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/go-openapi/errors v0.22.6 // indirect - github.com/go-openapi/strfmt v0.25.0 // indirect + github.com/go-openapi/errors v0.22.7 // indirect + github.com/go-openapi/strfmt v0.26.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect - github.com/google/cel-go v0.27.0 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/cel-go v0.28.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/connect-compress/v2 v2.1.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.21 // indirect github.com/mattn/go-runewidth v0.0.20 // indirect - github.com/minio/minlz v1.1.0 // indirect - github.com/oklog/ulid v1.3.1 // indirect + github.com/minio/minlz v1.1.1 // indirect + github.com/oklog/ulid/v2 v2.1.1 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/errors v1.2.0 // indirect github.com/olekukonko/ll v0.1.6 // indirect - github.com/olekukonko/tablewriter v1.1.3 // indirect + github.com/olekukonko/tablewriter v1.1.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -61,15 +80,14 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.6.0 // indirect - go.mongodb.org/mongo-driver v1.17.9 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.35.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect + golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.35.1 // indirect diff --git a/go.sum b/go.sum index 5f7458d..e31b7da 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 h1:PMmTMyvHScV9Mn8wc6ASge9uRcHy0jtqPd+fM35LmsQ= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= -buf.build/go/protovalidate v1.1.3 h1:m2GVEgQWd7rk+vIoAZ+f0ygGjvQTuqPQapBBdcpWVPE= -buf.build/go/protovalidate v1.1.3/go.mod h1:9XIuohWz+kj+9JVn3WQneHA5LZP50mjvneZMnbLkiIE= -buf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w= -buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q= -cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= -cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= -connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= -connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= +buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0= +buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4= +buf.build/go/protoyaml v0.7.0 h1:z4oVoFicbpPefhT7WAykxUdfp0yEQlhMQ2mCZOY5V38= +buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MGSQ0= +cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= +cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ= +connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4= connectrpc.com/validate v0.6.0 h1:DcrgDKt2ZScrUs/d/mh9itD2yeEa0UbBBa+i0mwzx+4= connectrpc.com/validate v0.6.0/go.mod h1:ihrpI+8gVbLH1fvVWJL1I3j0CfWnF8P/90LsmluRiZs= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= @@ -16,12 +16,10 @@ github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= -github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= -github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= +github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= +github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= +github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -29,18 +27,18 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-openapi/errors v0.22.6 h1:eDxcf89O8odEnohIXwEjY1IB4ph5vmbUsBMsFNwXWPo= -github.com/go-openapi/errors v0.22.6/go.mod h1:z9S8ASTUqx7+CP1Q8dD8ewGH/1JWFFLX/2PmAYNQLgk= -github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ= -github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA= +github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w= +github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c= +github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y= +github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= +github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= @@ -49,16 +47,16 @@ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo= -github.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw= +github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM= +github.com/google/cel-go v0.28.1/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/connect-compress/v2 v2.1.1 h1:ycZNp4rWOZBodVE2Ls5AzK4aHkyK+GteEfzRZgKNs+c= github.com/klauspost/connect-compress/v2 v2.1.1/go.mod h1:9oilsPHJMzGKkjafSBk9J7iVo4mO+dw0G0KSdVpnlVE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -67,28 +65,36 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= +github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +<<<<<<< HEAD github.com/metal-stack/api v0.0.58 h1:7UxnZrM41BS0f4S9RvqDg0/YTvs3FveawuyBoKz9WhA= github.com/metal-stack/api v0.0.58/go.mod h1:hEgtKVD7UnUwUExdA7pbFvVRxNRxSGUnU+bZce46//c= github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f h1:qTEfCIrCsE8YTSIhMiI2jYlDqO20K3S4pCNkB9wB3vQ= github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f/go.mod h1:u1wQl98JOfzyXqY7+0qD2xFSMnxvzCykkLgW80U1IrA= +======= +github.com/metal-stack/api v0.1.0 h1:V3nrarxGexnE0f1/2UtGCIAtjP815p7+yqQvruD0KJQ= +github.com/metal-stack/api v0.1.0/go.mod h1:wFU5aKfuurbBISQSIdJwBLQf4mTOBlERqWBzCafahEY= +github.com/metal-stack/metal-lib v0.25.1 h1:z14xNl59ueQavNvMG4wcIZGqVyosNlaNFcy8hUu3SCU= +github.com/metal-stack/metal-lib v0.25.1/go.mod h1:FWviUPM7oH1CnmCwkyLjWpd3yuzf6NnR97Xf45P2/Fk= +>>>>>>> main github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= -github.com/minio/minlz v1.1.0 h1:rUOGu3EP4EqJC5k3qCsIwEnZiJULKqtRyDdqbhlvMmQ= -github.com/minio/minlz v1.1.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/minio/minlz v1.1.1 h1:OGmft1V6AnI/Wme332U6bhG54nxEan+VFgkD7lat4KM= +github.com/minio/minlz v1.1.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= +github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo= github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= -github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA= -github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM= +github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= +github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -118,12 +124,11 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU= -go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +<<<<<<< HEAD golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= @@ -139,6 +144,32 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +======= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68 h1:WVVw1Nl19li0fMX++FJ3ye1z9+S1N35QODDy5qpnaXw= +google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:1dCETSCY2YKZNXQE3h4fun3TYwF5p8jejRKZgfWAgAY= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68 h1:PvEgGJf9C/1u5CHkInMg7UFYYUoiaQmW2LbtH0pjB78= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +>>>>>>> main google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/helpers/audit/audit.go b/pkg/helpers/audit/audit.go index 442d334..7a3c1b0 100644 --- a/pkg/helpers/audit/audit.go +++ b/pkg/helpers/audit/audit.go @@ -34,7 +34,7 @@ func ToPhase(phase string) *apiv2.AuditPhase { return new(apiv2.AuditPhase(p)) } -func TryPrettifyBody(trace *apiv2.AuditTrace) *apiv2.AuditTrace { +func TryPrettifyBody(trace *apiv2.AuditTrace) { if trace.Body != nil { trimmed := strings.Trim(*trace.Body, `"`) body := map[string]any{} @@ -44,6 +44,4 @@ func TryPrettifyBody(trace *apiv2.AuditTrace) *apiv2.AuditTrace { } } } - - return trace } diff --git a/tests/e2e/admin/audit_test.go b/tests/e2e/admin/audit_test.go new file mode 100644 index 0000000..847dafa --- /dev/null +++ b/tests/e2e/admin/audit_test.go @@ -0,0 +1,111 @@ +package admin_e2e + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/metal-stack/api/go/client" + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" +) + +func Test_AdminAuditCmd_List(t *testing.T) { + tests := []*e2e.Test[adminv2.AuditServiceListResponse, *apiv2.AuditTrace]{ + { + Name: "list", + CmdArgs: []string{"admin", "audit", "list"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.AuditServiceListRequest{ + Query: &apiv2.AuditQuery{}, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.AuditServiceListResponse{ + Traces: []*apiv2.AuditTrace{ + testresources.Trace1(), + testresources.Trace2(), + testresources.Trace3(), + }, + }) + }, + }, + }, + }, + ), + WantTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + 2001-01-01 00:00:00 5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE AlreadyExists + `), + WantWideTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY + 2001-01-01 00:00:00 5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST 1.2.3.4 result body + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST 1.2.3.4 request body + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE 1.2.3.4 AlreadyExists result body + `), + Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), + WantTemplate: new(`5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 1 +d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 1 +d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 2`), + WantMarkdown: new(` + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | + |---------------------|--------------------------------------|-------|--------------------------------------|----------------|----------------------|---------------| + | 2001-01-01 00:00:00 | 5091c4e9-e8db-483c-ab6b-fe14f82570a7 | Larry | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_REQUEST | | + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.Create/ | AUDIT_PHASE_REQUEST | | + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_RESPONSE | AlreadyExists | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AuditCmd_Describe(t *testing.T) { + tests := []*e2e.Test[adminv2.AuditServiceGetResponse, *apiv2.AuditTrace]{ + { + Name: "describe", + CmdArgs: []string{"admin", "audit", "describe", testresources.Trace1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.AuditServiceGetRequest{ + Uuid: testresources.Trace1().Uuid, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.AuditServiceGetResponse{ + Trace: testresources.Trace1(), + }) + }, + }, + }, + }), + WantObject: testresources.Trace1(), + WantProtoObject: testresources.Trace1(), + WantTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST + `), + WantWideTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST 1.2.3.4 request body + `), + Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), + WantTemplate: new(` +d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 1 + `), + WantMarkdown: new(` + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | + |---------------------|--------------------------------------|------|--------------------------------------|----------------|---------------------|------| + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.Create/ | AUDIT_PHASE_REQUEST | | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/admin/component_test.go b/tests/e2e/admin/component_test.go index ebf66b8..2db205b 100644 --- a/tests/e2e/admin/component_test.go +++ b/tests/e2e/admin/component_test.go @@ -9,6 +9,7 @@ import ( adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2erootcmd "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -55,23 +56,23 @@ func Test_AdminComponentCmd_Describe(t *testing.T) { tests := []*e2e.Test[adminv2.ComponentServiceGetResponse, *apiv2.Component]{ { Name: "describe", - CmdArgs: []string{"admin", "component", "describe", component1().Uuid}, + CmdArgs: []string{"admin", "component", "describe", testresources.Component1().Uuid}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ComponentServiceGetRequest{ - Uuid: component1().Uuid, + Uuid: testresources.Component1().Uuid, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.ComponentServiceGetResponse{ - Component: component1(), + Component: testresources.Component1(), }) }, }, }, }), - WantObject: component1(), - WantProtoObject: component1(), + WantObject: testresources.Component1(), + WantProtoObject: testresources.Component1(), WantTable: new(` ID TYPE IDENTIFIER STARTED AGE VERSION TOKEN TOKEN EXPIRES IN c1a2b3d4-e5f6-7890-abcd-ef1234567890 metal-core metal-core-1 0s 0s v1.0.0 t1a2b3d4-e5f6-7890-abcd-ef1234567890 1d @@ -110,8 +111,8 @@ func Test_AdminComponentCmd_List(t *testing.T) { WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.ComponentServiceListResponse{ Components: []*apiv2.Component{ - component1(), - component2(), + testresources.Component1(), + testresources.Component2(), }, }) }, @@ -150,22 +151,22 @@ func Test_AdminComponentCmd_Delete(t *testing.T) { tests := []*e2e.Test[adminv2.ComponentServiceDeleteResponse, *apiv2.Component]{ { Name: "delete", - CmdArgs: []string{"admin", "component", "delete", component1().Uuid}, + CmdArgs: []string{"admin", "component", "delete", testresources.Component1().Uuid}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ComponentServiceDeleteRequest{ - Uuid: component1().Uuid, + Uuid: testresources.Component1().Uuid, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.ComponentServiceDeleteResponse{ - Component: component1(), + Component: testresources.Component1(), }) }, }, }, }), - WantObject: component1(), + WantObject: testresources.Component1(), }, } for _, tt := range tests { diff --git a/tests/e2e/admin/image_test.go b/tests/e2e/admin/image_test.go new file mode 100644 index 0000000..f8349ae --- /dev/null +++ b/tests/e2e/admin/image_test.go @@ -0,0 +1,218 @@ +package admin_e2e + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/metal-stack/api/go/client" + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/spf13/afero" + "github.com/stretchr/testify/require" +) + +func Test_AdminImageCmd_Delete(t *testing.T) { + tests := []*e2e.Test[adminv2.ImageServiceDeleteResponse, *apiv2.Image]{ + { + Name: "delete", + CmdArgs: []string{"admin", "image", "delete", testresources.Image1().Id}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.ImageServiceDeleteRequest{ + Id: testresources.Image1().Id, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.ImageServiceDeleteResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantObject: testresources.Image1(), + WantProtoObject: testresources.Image1(), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + WantWideTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + Template: new("{{ .id }} {{ .name }}"), + WantTemplate: new(` + ubuntu-24.04 Ubuntu 24.04 + `), + WantMarkdown: new(` + | ID | NAME | DESCRIPTION | FEATURES | EXPIRATION | STATUS | + |--------------|--------------|------------------|----------|------------|-----------| + | ubuntu-24.04 | Ubuntu 24.04 | Ubuntu 24.04 LTS | machine | | supported | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminImageCmd_Create(t *testing.T) { + tests := []*e2e.Test[adminv2.ImageServiceCreateResponse, *apiv2.Image]{ + { + Name: "create", + CmdArgs: []string{"admin", "image", "create", + "--id", testresources.Image1().Id, + "--url", testresources.Image1().Url, + "--features", "machine", + "--classification", "supported", + "--description", *testresources.Image1().Description, + "--name", *testresources.Image1().Name}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.ImageServiceCreateRequest{ + Image: testresources.Image1(), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.ImageServiceCreateResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantObject: testresources.Image1(), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + }, + { + Name: "create from file", + CmdArgs: append([]string{"admin", "image", "create"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Image1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.ImageServiceCreateRequest{ + Image: testresources.Image1(), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.ImageServiceCreateResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + WantWideTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + Template: new("{{ .id }} {{ .name }}"), + WantTemplate: new(` + ubuntu-24.04 Ubuntu 24.04 + `), + WantMarkdown: new(` + | ID | NAME | DESCRIPTION | FEATURES | EXPIRATION | STATUS | + |--------------|--------------|------------------|----------|------------|-----------| + | ubuntu-24.04 | Ubuntu 24.04 | Ubuntu 24.04 LTS | machine | | supported | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminImageCmd_Update(t *testing.T) { + tests := []*e2e.Test[adminv2.ImageServiceUpdateResponse, *apiv2.Image]{ + { + Name: "update", + CmdArgs: []string{"admin", "image", "update", testresources.Image1().Id, "--name", *testresources.Image1().Name}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.ImageServiceUpdateRequest{ + Id: testresources.Image1().Id, + Name: testresources.Image1().Name, + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_SERVER, + }, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.ImageServiceUpdateResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantObject: testresources.Image1(), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + }, + { + Name: "update from file", + CmdArgs: append([]string{"admin", "image", "update"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Image1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.ImageServiceUpdateRequest{ + Id: testresources.Image1().Id, + Name: testresources.Image1().Name, + Description: testresources.Image1().Description, + Features: testresources.Image1().Features, + Classification: testresources.Image1().Classification, + ExpiresAt: testresources.Image1().ExpiresAt, + Url: new(testresources.Image1().Url), + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT, + }, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.ImageServiceUpdateResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + WantWideTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + Template: new("{{ .id }} {{ .name }}"), + WantTemplate: new(` + ubuntu-24.04 Ubuntu 24.04 + `), + WantMarkdown: new(` + | ID | NAME | DESCRIPTION | FEATURES | EXPIRATION | STATUS | + |--------------|--------------|------------------|----------|------------|-----------| + | ubuntu-24.04 | Ubuntu 24.04 | Ubuntu 24.04 LTS | machine | | supported | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/admin/switch_test.go b/tests/e2e/admin/switch_test.go index 3a7086a..368d12a 100644 --- a/tests/e2e/admin/switch_test.go +++ b/tests/e2e/admin/switch_test.go @@ -2,86 +2,56 @@ package admin_e2e import ( "testing" - "time" "connectrpc.com/connect" "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2erootcmd "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -var ( - switch1 = func() *apiv2.Switch { - return &apiv2.Switch{ - Id: "leaf01", - Partition: "fra-equ01", - Rack: new("rack-1"), - Description: "leaf switch 1", - ManagementIp: "10.0.0.1", - ManagementUser: new("admin"), - Os: &apiv2.SwitchOS{ - Vendor: apiv2.SwitchOSVendor_SWITCH_OS_VENDOR_SONIC, - Version: "4.2.0", - MetalCoreVersion: "v0.9.1 (abc1234), tags/v0.9.1", - }, - LastSync: &apiv2.SwitchSync{ - Time: timestamppb.New(e2e.TimeBubbleStartTime()), - Duration: durationpb.New(100 * time.Millisecond), - }, - Meta: &apiv2.Meta{ - CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), - }, - } - } - switch2 = func() *apiv2.Switch { - return &apiv2.Switch{ - Id: "leaf02", - Partition: "fra-equ01", - Rack: new("rack-1"), - Description: "leaf switch 2", - ManagementIp: "10.0.0.2", - ManagementUser: new("admin"), - Os: &apiv2.SwitchOS{ - Vendor: apiv2.SwitchOSVendor_SWITCH_OS_VENDOR_SONIC, - Version: "4.2.0", - MetalCoreVersion: "v0.9.1 (abc1234), tags/v0.9.1", - }, - LastSync: &apiv2.SwitchSync{ - Time: timestamppb.New(e2e.TimeBubbleStartTime()), - Duration: durationpb.New(200 * time.Millisecond), - }, - Meta: &apiv2.Meta{ - CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), - }, - } - } + "github.com/spf13/afero" + "github.com/stretchr/testify/require" ) func Test_AdminSwitchCmd_Describe(t *testing.T) { tests := []*e2e.Test[adminv2.SwitchServiceGetResponse, *apiv2.Switch]{ { Name: "describe", - CmdArgs: []string{"admin", "switch", "describe", switch1().Id}, + CmdArgs: []string{"admin", "switch", "describe", testresources.Switch2()}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceGetRequest{ - Id: switch1().Id, + Id: testresources.Switch2().Id, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.SwitchServiceGetResponse{ - Switch: switch1(), + Switch: testresources.Switch2(), }) }, }, }, }), - WantObject: switch1(), - WantProtoObject: switch1(), + WantObject: testresources.Switch2(), + WantProtoObject: testresources.Switch2(), + WantDefault: new(` +description: leaf switch 2 +id: leaf02 +lastSync: + duration: 0.200s + time: "2000-01-01T00:00:00Z" +managementIp: 10.0.0.2 +managementUser: admin +meta: + createdAt: "2000-01-01T00:00:00Z" +os: + metalCoreVersion: v0.9.1 (abc1234), tags/v0.9.1 + vendor: SWITCH_OS_VENDOR_SONIC + version: 4.2.0 +partition: fra-equ01 +rack: rack-1 + `), }, } for _, tt := range tests { @@ -105,8 +75,8 @@ func Test_AdminSwitchCmd_List(t *testing.T) { WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.SwitchServiceListResponse{ Switches: []*apiv2.Switch{ - switch1(), - switch2(), + testresources.Switch1(), + testresources.Switch2(), }, }) }, @@ -145,22 +115,350 @@ func Test_AdminSwitchCmd_Delete(t *testing.T) { tests := []*e2e.Test[adminv2.SwitchServiceDeleteResponse, *apiv2.Switch]{ { Name: "delete", - CmdArgs: []string{"admin", "switch", "delete", switch1().Id}, + CmdArgs: []string{"admin", "switch", "delete", testresources.Switch2().Id}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceDeleteRequest{ - Id: switch1().Id, + Id: testresources.Switch2().Id, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&adminv2.SwitchServiceDeleteResponse{ - Switch: switch1(), + Switch: testresources.Switch2(), }) }, }, }, }), - WantObject: switch1(), + WantObject: testresources.Switch2(), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminSwitchCmd_Update(t *testing.T) { + tests := []*e2e.Test[adminv2.SwitchServiceUpdateResponse, *apiv2.Switch]{ + { + Name: "update from file", + CmdArgs: append([]string{"admin", "switch", "update"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Switch2()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServiceUpdateRequest{ + Id: testresources.Switch2().Id, + Description: new(testresources.Switch2().Description), + ManagementIp: new(testresources.Switch2().ManagementIp), + ManagementUser: testresources.Switch2().ManagementUser, + Os: testresources.Switch2().Os, + ReplaceMode: new(testresources.Switch2().ReplaceMode), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServiceUpdateResponse{ + Switch: testresources.Switch2(), + }) + }, + }, + }, + }), + WantTable: new(` + ID PARTITION RACK OS STATUS LAST SYNC + leaf02 fra-equ01 rack-1 🦔 ● + `), + WantWideTable: new(` + ID PARTITION RACK OS METALCORE IP MODE LAST SYNC SYNC DURATION LAST ERROR + leaf02 fra-equ01 rack-1 SONiC (4.2.0) v0.9.1 (abc1234) 10.0.0.2 operational 200ms + `), + Template: new("{{ .id }} {{ .os.metal_core_version }}"), + WantTemplate: new(`leaf02 v0.9.1 (abc1234), tags/v0.9.1`), + WantMarkdown: new(` + | ID | PARTITION | RACK | OS | STATUS | LAST SYNC | + |--------|-----------|--------|----|--------|-----------| + | leaf02 | fra-equ01 | rack-1 | 🦔 | ● | | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminSwitchCmd_ConnectedMachines(t *testing.T) { + tests := []*e2e.Test[adminv2.SwitchServiceConnectedMachinesResponse, *apiv2.Switch]{ + { + Name: "connected machines", + CmdArgs: []string{"admin", "switch", "connected-machines"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServiceConnectedMachinesRequest{ + Query: &apiv2.SwitchQuery{}, + MachineQuery: &apiv2.MachineQuery{}, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServiceConnectedMachinesResponse{ + SwitchesWithMachines: []*apiv2.SwitchWithMachines{testresources.SwitchWithMachines1()}, + }) + }, + }, + }, + }), + WantTable: new(` + ID NIC NAME IDENTIFIER PARTITION RACK SIZE PRODUCT SERIAL CHASSIS SERIAL + leaf01 fra-equ01 rack-1 + └─╴id1 Ethernet0 (up) oid:0x1000000000001 fra-equ01 rack-1 m1-small ps-1 cs-1 + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminSwitchCmd_Detail(t *testing.T) { + tests := []*e2e.Test[adminv2.SwitchServiceListResponse, apiv2.Switch]{ + { + Name: "list", + CmdArgs: []string{"admin", "switch", "detail", testresources.Switch1().Id}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServiceListRequest{ + Query: &apiv2.SwitchQuery{ + Os: &apiv2.SwitchOSQuery{}, + }, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServiceListResponse{ + Switches: []*apiv2.Switch{ + testresources.Switch1(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + PARTITION RACK SWITCH PORT MACHINE VNI - FILTER CIDR - FILTER + fra-equ01 rack-1 leaf01 Ethernet0 id1 10001 10.0.0.0/24 + 10002 192.168.100.0/24 + `), + Template: new("{{ .id }} {{ .partition }} {{ .rack }}"), + WantTemplate: new(`leaf01 fra-equ01 rack-1`), + WantMarkdown: new(` + | PARTITION | RACK | SWITCH | PORT | MACHINE | VNI - FILTER | CIDR - FILTER | + |-----------|--------|--------|-----------|---------|--------------|------------------| + | fra-equ01 | rack-1 | leaf01 | Ethernet0 | id1 | 10001 | 10.0.0.0/24 | + | | | | | | 10002 | 192.168.100.0/24 | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminSwitchCmd_Migrate(t *testing.T) { + tests := []*e2e.Test[adminv2.SwitchServiceMigrateResponse, *apiv2.Switch]{ + { + Name: "describe", + CmdArgs: []string{"admin", "switch", "migrate", testresources.Switch1().Id, testresources.Switch2().Id}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServiceMigrateRequest{ + OldSwitch: testresources.Switch1().Id, + NewSwitch: testresources.Switch2().Id, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServiceMigrateResponse{ + Switch: testresources.Switch2(), + }) + }, + }, + }, + }), + WantDefault: new(` +switch: + description: leaf switch 2 + id: leaf02 + lastSync: + duration: 0.200s + time: "2000-01-01T00:00:00Z" + managementIp: 10.0.0.2 + managementUser: admin + meta: + createdAt: "2000-01-01T00:00:00Z" + os: + metalCoreVersion: v0.9.1 (abc1234), tags/v0.9.1 + vendor: SWITCH_OS_VENDOR_SONIC + version: 4.2.0 + partition: fra-equ01 + rack: rack-1 + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminSwitchCmd_Port(t *testing.T) { + tests := []*e2e.Test[adminv2.SwitchServicePortResponse, *apiv2.Switch]{ + { + Name: "port up", + CmdArgs: []string{"admin", "switch", "port", "up", testresources.Switch1().Id, "--port", testresources.Nic1().Name}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServicePortRequest{ + Id: testresources.Switch1().Id, + NicName: testresources.Nic1().Name, + Status: apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_UP, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServicePortResponse{ + Switch: testresources.Switch1(), + }) + }, + }, + }, + }), + Template: new("{{ .Actual.machine_id }} {{ .Actual.nic.name }} {{ .Desired.name }}"), + WantTemplate: new(`id1 Ethernet0 Ethernet0`), + WantDefault: new(` +--- +Actual: + machine_id: id1 + nic: + bgp_filter: + cidrs: + - 10.0.0.0/24 + - 192.168.100.0/24 + vnis: + - "10001" + - "10002" + bgp_port_state: + accepted_prefix_counter: 118 + bgp_state: 6 + bgp_timer_up_established: + seconds: 946677600 + neighbor: 10.0.0.2 + peer_group: TOR-LEAFS + sent_prefix_counter: 120 + vrf_name: default + identifier: oid:0x1000000000001 + mac: 52:54:00:ab:cd:01 + name: Ethernet0 + state: + actual: 1 + desired: 1 + vrf: default +Desired: + bgp_filter: + cidrs: + - 10.0.0.0/24 + - 192.168.100.0/24 + vnis: + - "10001" + - "10002" + bgp_port_state: + accepted_prefix_counter: 118 + bgp_state: 6 + bgp_timer_up_established: + seconds: 946677600 + neighbor: 10.0.0.2 + peer_group: TOR-LEAFS + sent_prefix_counter: 120 + vrf_name: default + identifier: oid:0x1000000000001 + mac: 52:54:00:ab:cd:01 + name: Ethernet0 + state: + actual: 1 + desired: 1 + vrf: default +`), + }, + { + Name: "down", + CmdArgs: []string{"admin", "switch", "port", "down", testresources.Switch1().Id, "--port", testresources.Nic1().Name}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.SwitchServicePortRequest{ + Id: testresources.Switch1().Id, + NicName: testresources.Nic1().Name, + Status: apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_DOWN, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.SwitchServicePortResponse{ + Switch: testresources.Switch1(), + }) + }, + }, + }, + }), + Template: new("{{ .Actual.machine_id }} {{ .Actual.nic.name }} {{ .Desired.name }}"), + WantTemplate: new(`id1 Ethernet0 Ethernet0`), + WantDefault: new(` +--- +Actual: + machine_id: id1 + nic: + bgp_filter: + cidrs: + - 10.0.0.0/24 + - 192.168.100.0/24 + vnis: + - "10001" + - "10002" + bgp_port_state: + accepted_prefix_counter: 118 + bgp_state: 6 + bgp_timer_up_established: + seconds: 946677600 + neighbor: 10.0.0.2 + peer_group: TOR-LEAFS + sent_prefix_counter: 120 + vrf_name: default + identifier: oid:0x1000000000001 + mac: 52:54:00:ab:cd:01 + name: Ethernet0 + state: + actual: 1 + desired: 1 + vrf: default +Desired: + bgp_filter: + cidrs: + - 10.0.0.0/24 + - 192.168.100.0/24 + vnis: + - "10001" + - "10002" + bgp_port_state: + accepted_prefix_counter: 118 + bgp_state: 6 + bgp_timer_up_established: + seconds: 946677600 + neighbor: 10.0.0.2 + peer_group: TOR-LEAFS + sent_prefix_counter: 120 + vrf_name: default + identifier: oid:0x1000000000001 + mac: 52:54:00:ab:cd:01 + name: Ethernet0 + state: + actual: 1 + desired: 1 + vrf: default + `), }, } for _, tt := range tests { diff --git a/tests/e2e/admin/task_test.go b/tests/e2e/admin/task_test.go new file mode 100644 index 0000000..d8194fe --- /dev/null +++ b/tests/e2e/admin/task_test.go @@ -0,0 +1,203 @@ +package admin_e2e + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/metal-stack/api/go/client" + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" +) + +func Test_AdminTaskCmd_List(t *testing.T) { + tests := []*e2e.Test[adminv2.TaskServiceListResponse, adminv2.TaskInfo]{ + { + Name: "list", + CmdArgs: []string{"admin", "task", "list"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.TaskServiceListRequest{}, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.TaskServiceListResponse{ + Tasks: []*adminv2.TaskInfo{ + testresources.Task1(), + testresources.Task2(), + }, + }) + }, + }, + }, + }), + Template: new("{{ .id }} {{ .type }}"), + WantTemplate: new(` +00dc6a98-bd80-787a-9725-ffb692d83261 image-provision +00dc6ab4-34c0-73ce-af77-3e07748d0e0d firewall-update + `), + WantTable: new(` + ID QUEUE WHEN TYPE STATE + 00dc6a98-bd80-787a-9725-ffb692d83261 default 1h ago image-provision active + 00dc6ab4-34c0-73ce-af77-3e07748d0e0d default 30m ago firewall-update pending + `), + WantWideTable: new(` + ID QUEUE WHEN TYPE STATE ISSUED AT PAYLOAD RESULT + 00dc6a98-bd80-787a-9725-ffb692d83261 default 1h ago image-provision active 1999-12-31 23:00:00 +0000 UTC {"machine_id":"machine1"} + 00dc6ab4-34c0-73ce-af77-3e07748d0e0d default 30m ago firewall-update pending 1999-12-31 23:30:00 +0000 UTC {"firewall_id":"fw1"} + `), + WantMarkdown: new(` + | ID | QUEUE | WHEN | TYPE | STATE | + |--------------------------------------|---------|---------|-----------------|---------| + | 00dc6a98-bd80-787a-9725-ffb692d83261 | default | 1h ago | image-provision | active | + | 00dc6ab4-34c0-73ce-af77-3e07748d0e0d | default | 30m ago | firewall-update | pending | + `), + }, + { + Name: "list with queue filter", + CmdArgs: []string{"admin", "task", "list", "--queue", "high-priority"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.TaskServiceListRequest{ + Queue: func() *string { s := "high-priority"; return &s }(), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.TaskServiceListResponse{ + Tasks: []*adminv2.TaskInfo{ + testresources.Task3(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + ID QUEUE WHEN TYPE STATE + 00dc6ab5-1f20-7426-a397-8644fb78324e high-priority 29m ago machine-reimage completed + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminTaskCmd_Describe(t *testing.T) { + tests := []*e2e.Test[adminv2.TaskServiceGetResponse, *adminv2.TaskInfo]{ + { + Name: "describe", + CmdArgs: []string{"admin", "task", "describe", testresources.Task1().Id}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.TaskServiceGetRequest{ + TaskId: testresources.Task1().Id, + Queue: "default", + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.TaskServiceGetResponse{ + Task: testresources.Task1(), + }) + }, + }, + }, + }), + WantObject: testresources.Task1(), + WantProtoObject: testresources.Task1(), + Template: new("{{ .id }} {{ .type }}"), + WantTemplate: new(` +00dc6a98-bd80-787a-9725-ffb692d83261 image-provision + `), + }, + { + Name: "describe with queue", + CmdArgs: []string{"admin", "task", "describe", testresources.Task3().Id, "--queue", "high-priority"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.TaskServiceGetRequest{ + TaskId: testresources.Task3().Id, + Queue: "high-priority", + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.TaskServiceGetResponse{ + Task: testresources.Task3(), + }) + }, + }, + }, + }), + WantObject: testresources.Task3(), + WantProtoObject: testresources.Task3(), + Template: new("{{ .id }} {{ .queue }} {{ .type }}"), + WantTemplate: new(` +00dc6ab5-1f20-7426-a397-8644fb78324e high-priority machine-reimage + `), + WantTable: new(` + ID QUEUE WHEN TYPE STATE + 00dc6ab5-1f20-7426-a397-8644fb78324e high-priority 29m ago machine-reimage completed + `), + WantWideTable: new(` + ID QUEUE WHEN TYPE STATE ISSUED AT PAYLOAD RESULT + 00dc6ab5-1f20-7426-a397-8644fb78324e high-priority 29m ago machine-reimage completed 1999-12-31 23:31:00 +0000 UTC {"machine_id":"machine2"} success + `), + WantMarkdown: new(` + | ID | QUEUE | WHEN | TYPE | STATE | + |--------------------------------------|---------------|---------|-----------------|-----------| + | 00dc6ab5-1f20-7426-a397-8644fb78324e | high-priority | 29m ago | machine-reimage | completed | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_AdminTaskQueuesCmd(t *testing.T) { + tests := []*e2e.Test[adminv2.TaskServiceQueuesResponse, any]{ + { + Name: "queues", + CmdArgs: []string{"admin", "task", "queues"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &adminv2.TaskServiceQueuesRequest{}, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&adminv2.TaskServiceQueuesResponse{ + Queues: []string{"default", "high-priority", "low-priority"}, + }) + }, + }, + }, + }), + WantTable: new(` + QUEUE + default + high-priority + low-priority + `), + WantWideTable: new(` + QUEUE + default + high-priority + low-priority + `), + WantMarkdown: new(` + | QUEUE | + |---------------| + | default | + | high-priority | + | low-priority | + `), + Template: new(`{{ range .queues }}{{ . }}{{ "\n" }}{{ end }}`), + WantTemplate: new(` +default +high-priority +low-priority + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/admin/token_test.go b/tests/e2e/admin/token_test.go index 136a50b..6901af8 100644 --- a/tests/e2e/admin/token_test.go +++ b/tests/e2e/admin/token_test.go @@ -33,14 +33,14 @@ func Test_AdminTokenCmd_List(t *testing.T) { }, }), WantTable: new(` - TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES - TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) - TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 0 2000-01-03 00:00:00 UTC (in 2d) + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) + TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 2 2000-01-03 00:00:00 UTC (in 2d) `), WantWideTable: new(` - TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES - TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) - TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 0 2000-01-03 00:00:00 UTC (in 2d) + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) + TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 2 2000-01-03 00:00:00 UTC (in 2d) `), Template: new("{{ .uuid }} {{ .description }}"), WantTemplate: new(` @@ -48,10 +48,10 @@ a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 ci token b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev token `), WantMarkdown: new(` - | TYPE | ID | ADMIN | USER | DESCRIPTION | ROLES | PERMS | EXPIRES | - |----------------|--------------------------------------|-------|----------------------|-------------|-------|-------|---------------------------------| - | TOKEN_TYPE_API | a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 | | admin@metal-stack.io | ci token | 0 | 0 | 2000-01-02 00:00:00 UTC (in 1d) | - | TOKEN_TYPE_API | b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 | | dev@metal-stack.io | dev token | 0 | 0 | 2000-01-03 00:00:00 UTC (in 2d) | + | TYPE | ID | ADMIN | USER | DESCRIPTION | ROLES | PERMS | EXPIRES | + |----------------|--------------------------------------|-------|----------------------|-------------|-------|-------|---------------------------------| + | TOKEN_TYPE_API | a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 | | admin@metal-stack.io | ci token | 0 | 0 | 2000-01-02 00:00:00 UTC (in 1d) | + | TOKEN_TYPE_API | b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 | | dev@metal-stack.io | dev token | 0 | 2 | 2000-01-03 00:00:00 UTC (in 2d) | `), }, } diff --git a/tests/e2e/api/audit_test.go b/tests/e2e/api/audit_test.go index dc7afd5..fd7b976 100644 --- a/tests/e2e/api/audit_test.go +++ b/tests/e2e/api/audit_test.go @@ -2,6 +2,7 @@ package api_e2e import ( "testing" + "time" "connectrpc.com/connect" "github.com/metal-stack/api/go/client" @@ -9,58 +10,71 @@ import ( e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" - "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/timestamppb" ) -var ( - Trace1 = func() *apiv2.AuditTrace { - return &apiv2.AuditTrace{ - Uuid: "d1ff7267-2fbb-4a63-a7c1-44f1a83381a7", - Timestamp: timestamppb.New(e2e.TimeBubbleStartTime()), - User: "me", - Tenant: "a", - Project: &testresources.Project1().Uuid, - Method: "/apiv2.List/", - Body: new("request body"), - SourceIp: "1.2.3.4", - Phase: apiv2.AuditPhase_AUDIT_PHASE_REQUEST, - } - } - - Trace2 = func() *apiv2.AuditTrace { - return &apiv2.AuditTrace{ - Uuid: "d1ff7267-2fbb-4a63-a7c1-44f1a83381a7", - Timestamp: timestamppb.New(e2e.TimeBubbleStartTime()), - User: "me", - Tenant: "a", - Project: &testresources.Project1().Uuid, - Method: "/apiv2.List/", - Body: new("result body"), - SourceIp: "1.2.3.4", - ResultCode: new(int32(codes.AlreadyExists)), - Phase: apiv2.AuditPhase_AUDIT_PHASE_RESPONSE, - } - } -) - func Test_AuditCmd_List(t *testing.T) { tests := []*e2e.Test[apiv2.ImageServiceListResponse, *apiv2.Image]{ { Name: "list", - CmdArgs: []string{"audit", "list", "--tenant", "a"}, + CmdArgs: []string{"audit", "list", "--tenant", testresources.Trace1().Tenant}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceListRequest{ - Login: "a", + Login: testresources.Trace1().Tenant, Query: &apiv2.AuditQuery{}, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&apiv2.AuditServiceListResponse{ Traces: []*apiv2.AuditTrace{ - Trace1(), - Trace2(), + testresources.Trace1(), + testresources.Trace2(), + }, + }) + }, + }, + }, + }, + ), + WantTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE AlreadyExists + `), + WantWideTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST 1.2.3.4 request body + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE 1.2.3.4 AlreadyExists result body + `), + Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), + WantTemplate: new(`d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 1 +d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 2`), + WantMarkdown: new(` + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | + |---------------------|--------------------------------------|------|--------------------------------------|----------------|----------------------|---------------| + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.Create/ | AUDIT_PHASE_REQUEST | | + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_RESPONSE | AlreadyExists | + `), + }, + { + Name: "list", + CmdArgs: []string{"audit", "list", "--tenant", testresources.Trace3().Tenant, "--from", timestamppb.New(time.Date(2000, 12, 24, 0, 0, 0, 0, time.UTC)).AsTime().Format("2006-01-02 15:04:05"), "--to", timestamppb.New(time.Date(2001, 1, 2, 0, 0, 0, 0, time.UTC)).AsTime().Format("2006-01-02 15:04:05"), "--user", testresources.Trace3().User}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.AuditServiceListRequest{ + Login: testresources.Trace3().Tenant, + Query: &apiv2.AuditQuery{ + User: new(testresources.Trace3().User), + From: timestamppb.New(time.Date(2000, 12, 24, 0, 0, 0, 0, time.UTC)), + To: timestamppb.New(time.Date(2001, 1, 2, 0, 0, 0, 0, time.UTC)), + }, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.AuditServiceListResponse{ + Traces: []*apiv2.AuditTrace{ + testresources.Trace3(), }, }) }, @@ -69,25 +83,52 @@ func Test_AuditCmd_List(t *testing.T) { }, ), WantTable: new(` - TIME REQUEST ID USER PROJECT METHOD PHASE CODE - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE AlreadyExists + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + 2001-01-01 00:00:00 5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST `), WantWideTable: new(` - TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST 1.2.3.4 request body - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_RESPONSE 1.2.3.4 AlreadyExists result body + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY + 2001-01-01 00:00:00 5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST 1.2.3.4 result body `), Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), WantTemplate: new(` -d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 1 -d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 2 + 5091c4e9-e8db-483c-ab6b-fe14f82570a7 Larry 1 + `), + WantMarkdown: new(` + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | + |---------------------|--------------------------------------|-------|--------------------------------------|--------------|---------------------|------| + | 2001-01-01 00:00:00 | 5091c4e9-e8db-483c-ab6b-fe14f82570a7 | Larry | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_REQUEST | | + `), + }, + { + Name: "list", + CmdArgs: []string{"audit", "list", "--tenant", "notExisting"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.AuditServiceListRequest{ + Login: "notExisting", + Query: &apiv2.AuditQuery{}, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.AuditServiceListResponse{ + Traces: []*apiv2.AuditTrace{}, + }) + }, + }, + }, + }, + ), + WantTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + `), + WantWideTable: new(` + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY `), + Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), + WantTemplate: new(``), WantMarkdown: new(` - | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | - |---------------------|--------------------------------------|------|--------------------------------------|--------------|----------------------|---------------| - | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_REQUEST | | - | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_RESPONSE | AlreadyExists | + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | `), }, } @@ -100,40 +141,40 @@ func Test_AuditCmd_Describe(t *testing.T) { tests := []*e2e.Test[apiv2.AuditServiceGetResponse, *apiv2.AuditTrace]{ { Name: "describe", - CmdArgs: []string{"audit", "describe", "--tenant", "a", Trace1().Uuid}, + CmdArgs: []string{"audit", "describe", "--tenant", testresources.Trace1().Tenant, testresources.Trace1().Uuid}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceGetRequest{ - Login: "a", - Uuid: Trace1().Uuid, + Login: testresources.Trace1().Tenant, + Uuid: testresources.Trace1().Uuid, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&apiv2.AuditServiceGetResponse{ - Trace: Trace1(), + Trace: testresources.Trace1(), }) }, }, }, }), - WantObject: Trace1(), - WantProtoObject: Trace1(), + WantObject: testresources.Trace1(), + WantProtoObject: testresources.Trace1(), WantTable: new(` - TIME REQUEST ID USER PROJECT METHOD PHASE CODE - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST + TIME REQUEST ID USER PROJECT METHOD PHASE CODE + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST `), WantWideTable: new(` - TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY - 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.List/ AUDIT_PHASE_REQUEST 1.2.3.4 request body + TIME REQUEST ID USER PROJECT METHOD PHASE SOURCE IP CODE BODY + 2000-01-01 00:00:00 d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 0d81bca7-73f6-4da3-8397-4a8c52a0c583 /apiv2.Create/ AUDIT_PHASE_REQUEST 1.2.3.4 request body `), Template: new("{{ .uuid }} {{ .user }} {{ .phase }}"), WantTemplate: new(` d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 1 `), WantMarkdown: new(` - | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | - |---------------------|--------------------------------------|------|--------------------------------------|--------------|---------------------|------| - | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.List/ | AUDIT_PHASE_REQUEST | | + | TIME | REQUEST ID | USER | PROJECT | METHOD | PHASE | CODE | + |---------------------|--------------------------------------|------|--------------------------------------|----------------|---------------------|------| + | 2000-01-01 00:00:00 | d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 | me | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | /apiv2.Create/ | AUDIT_PHASE_REQUEST | | `), }, } diff --git a/tests/e2e/api/image_test.go b/tests/e2e/api/image_test.go index 14c13af..3941a3b 100644 --- a/tests/e2e/api/image_test.go +++ b/tests/e2e/api/image_test.go @@ -106,3 +106,48 @@ func Test_ImageCmd_Describe(t *testing.T) { tt.TestCmd(t) } } + +func Test_ImageCmd_Latest(t *testing.T) { + tests := []*e2e.Test[apiv2.ImageServiceLatestResponse, *apiv2.Image]{ + { + Name: "latest", + CmdArgs: []string{"image", "latest", "--os", testresources.Image1().Id}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ImageServiceLatestRequest{ + Os: testresources.Image1().Id, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ImageServiceLatestResponse{ + Image: testresources.Image1(), + }) + }, + }, + }, + }), + WantObject: testresources.Image1(), + WantProtoObject: testresources.Image1(), + WantTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + WantWideTable: new(` + ID NAME DESCRIPTION FEATURES EXPIRATION STATUS + ubuntu-24.04 Ubuntu 24.04 Ubuntu 24.04 LTS machine supported + `), + Template: new("{{ .id }} {{ .name }}"), + WantTemplate: new(` + ubuntu-24.04 Ubuntu 24.04 + `), + WantMarkdown: new(` + | ID | NAME | DESCRIPTION | FEATURES | EXPIRATION | STATUS | + |--------------|--------------|------------------|----------|------------|-----------| + | ubuntu-24.04 | Ubuntu 24.04 | Ubuntu 24.04 LTS | machine | | supported | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/api/ip_test.go b/tests/e2e/api/ip_test.go index 45053f2..be9fdcd 100644 --- a/tests/e2e/api/ip_test.go +++ b/tests/e2e/api/ip_test.go @@ -251,48 +251,21 @@ func Test_IPCmd_Delete(t *testing.T) { } func Test_IPCmd_Update(t *testing.T) { - tests := []*e2e.Test[apiv2.IPServiceDeleteResponse, *apiv2.IP]{ + tests := []*e2e.Test[apiv2.IPServiceUpdateResponse, *apiv2.IP]{ { Name: "update", CmdArgs: []string{"ip", "update", "--project", testresources.IP1().Project, testresources.IP1().Ip, "--name", "foo"}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ - // TODO: the client gets the IP two times? - { - WantRequest: &apiv2.IPServiceGetRequest{ - Ip: testresources.IP1().Ip, - Project: testresources.IP1().Project, - }, - WantResponse: func() connect.AnyResponse { - return connect.NewResponse(&apiv2.IPServiceGetResponse{ - Ip: testresources.IP1(), - }) - }, - }, - { - WantRequest: &apiv2.IPServiceGetRequest{ - Ip: testresources.IP1().Ip, - Project: testresources.IP1().Project, - }, - WantResponse: func() connect.AnyResponse { - return connect.NewResponse(&apiv2.IPServiceGetResponse{ - Ip: testresources.IP1(), - }) - }, - }, { WantRequest: &apiv2.IPServiceUpdateRequest{ Ip: testresources.IP1().Ip, Project: testresources.IP1().Project, Name: new("foo"), - - // TODO: these fields do not need to be sent? - Description: &testresources.IP1().Description, - Labels: &apiv2.UpdateLabels{ - Update: &apiv2.Labels{}, + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_SERVER, }, - Type: &testresources.IP1().Type, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&apiv2.IPServiceUpdateResponse{ @@ -304,6 +277,14 @@ func Test_IPCmd_Update(t *testing.T) { }, ), WantObject: testresources.IP1(), + WantTable: new(` + IP PROJECT ID TYPE NAME ATTACHED SERVICE + 1.1.1.1 ce19a655-7933-4745-8f3e-9592b4a90488 2e0144a2-09ef-42b7-b629-4263295db6e8 static a + `), + WantWideTable: new(` + IP PROJECT ID TYPE NAME DESCRIPTION LABELS + 1.1.1.1 ce19a655-7933-4745-8f3e-9592b4a90488 2e0144a2-09ef-42b7-b629-4263295db6e8 static a a description cluster.metal-stack.io/id/namespace/service=/default/ingress-nginx + `), }, { Name: "update from file", @@ -335,6 +316,9 @@ func Test_IPCmd_Update(t *testing.T) { }, Name: &testresources.IP1().Name, Type: &testresources.IP1().Type, + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT, + }, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&apiv2.IPServiceUpdateResponse{ @@ -357,7 +341,7 @@ func Test_IPCmd_Update(t *testing.T) { } func Test_IPCmd_Apply(t *testing.T) { - tests := []*e2e.Test[apiv2.IPServiceDeleteResponse, *apiv2.IP]{ + tests := []*e2e.Test[apiv2.IPServiceUpdateResponse, *apiv2.IP]{ { Name: "apply", CmdArgs: append([]string{"ip", "apply"}, e2e.AppendFromFileCommonArgs()...), @@ -457,6 +441,9 @@ func Test_IPCmd_Apply(t *testing.T) { }, Name: &testresources.IP1().Name, Type: &testresources.IP1().Type, + UpdateMeta: &apiv2.UpdateMeta{ + LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT, + }, }, WantResponse: func() connect.AnyResponse { return connect.NewResponse(&apiv2.IPServiceUpdateResponse{ diff --git a/tests/e2e/api/project_test.go b/tests/e2e/api/project_test.go index 343bf1b..42fac6e 100644 --- a/tests/e2e/api/project_test.go +++ b/tests/e2e/api/project_test.go @@ -1,9 +1,11 @@ package api_e2e import ( + "fmt" "testing" "connectrpc.com/connect" + "github.com/dustin/go-humanize" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2erootcmd "github.com/metal-stack/cli/testing/e2e" @@ -310,3 +312,334 @@ f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c project-b tt.TestCmd(t) } } + +func Test_ProjectCmd_Apply(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceUpdateResponse, *apiv2.Project]{ + { + Name: "apply", + CmdArgs: append([]string{"project", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceCreateRequest{ + Login: testresources.Project1().Tenant, + Name: testresources.Project1().Name, + Description: testresources.Project1().Description, + Labels: testresources.Project1().Meta.Labels, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceCreateResponse{ + Project: testresources.Project1(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + ID TENANT NAME DESCRIPTION CREATION DATE + 0d81bca7-73f6-4da3-8397-4a8c52a0c583 metal-stack project-a first project 2000-01-01 00:00:00 UTC + `), + }, + { + Name: "apply already exists", + CmdArgs: append([]string{"project", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceCreateRequest{ + Login: testresources.Project1().Tenant, + Name: testresources.Project1().Name, + Description: testresources.Project1().Description, + }, + WantError: connect.NewError(connect.CodeAlreadyExists, fmt.Errorf("already exists")), + }, + { + WantRequest: &apiv2.ProjectServiceUpdateRequest{ + Project: testresources.Project1().Uuid, + Description: &testresources.Project1().Description, + Name: &testresources.Project1().Name, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceUpdateResponse{ + Project: testresources.Project1(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + ID TENANT NAME DESCRIPTION CREATION DATE + 0d81bca7-73f6-4da3-8397-4a8c52a0c583 metal-stack project-a first project 2000-01-01 00:00:00 UTC + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_ListInvites(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceInvitesListResponse, apiv2.ProjectInvite]{ + { + Name: "list invites", + CmdArgs: []string{"project", "invite", "list", testresources.Project1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceInvitesListRequest{}, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceInvitesListResponse{ + Invites: []*apiv2.ProjectInvite{ + testresources.Project1Invite(), + testresources.Project2Invite(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + SECRET PROJECT ROLE EXPIRES IN + secret 0d81bca7-73f6-4da3-8397-4a8c52a0c583 PROJECT_ROLE_EDITOR 2 days from now + secret f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c PROJECT_ROLE_EDITOR 2 days from now + `), + WantWideTable: new(` + SECRET PROJECT ROLE EXPIRES IN + secret 0d81bca7-73f6-4da3-8397-4a8c52a0c583 PROJECT_ROLE_EDITOR 2 days from now + secret f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c PROJECT_ROLE_EDITOR 2 days from now + `), + Template: new("{{ .project }} {{ .role }}"), + WantTemplate: new(` +0d81bca7-73f6-4da3-8397-4a8c52a0c583 2 +f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c 2 + `), + WantMarkdown: new(` + | SECRET | PROJECT | ROLE | EXPIRES IN | + |--------|--------------------------------------|---------------------|-----------------| + | secret | 0d81bca7-73f6-4da3-8397-4a8c52a0c583 | PROJECT_ROLE_EDITOR | 2 days from now | + | secret | f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c | PROJECT_ROLE_EDITOR | 2 days from now | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_DeleteInvite(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceInviteDeleteResponse, string]{ + { + Name: "delete", + CmdArgs: []string{"project", "invite", "delete", testresources.Project1Invite().Secret, "--project", testresources.Project1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceInviteDeleteRequest{ + Project: testresources.Project1().Uuid, + Secret: testresources.Project1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceInviteDeleteResponse{}) + }, + }, + }, + }), + WantMarkdown: new(""), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_CreateInvite(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceInviteRequest, string]{ + { + Name: "create invite", + CmdArgs: []string{"project", "invite", "generate-join-secret", "--role", testresources.Project1Invite().Role.String(), "--project", testresources.Project1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceInviteRequest{ + Project: testresources.Project1().Uuid, + Role: testresources.Project1Invite().Role, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceInviteResponse{ + Invite: testresources.Project1Invite(), + }) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("You can share this secret with the member to join, it expires in %s:\n\n%s (https://console.metal-stack.io/project-invite/%s)", + humanize.RelTime(e2e.TimeBubbleStartTime(), testresources.Project1Invite().ExpiresAt.AsTime(), "from now", "ago"), + testresources.Project1Invite().Secret, + testresources.Project1Invite().Secret, + )), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_Join(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceInviteAcceptResponse, string]{ + { + Name: "join", + CmdArgs: []string{"project", "invite", "join", testresources.Project1Invite().Secret}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceInviteGetRequest{ + Secret: testresources.Project1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceInviteGetResponse{ + Invite: testresources.Project1Invite(), + }) + }, + }, + { + WantRequest: &apiv2.ProjectServiceInviteAcceptRequest{ + Secret: testresources.Project1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceInviteAcceptResponse{ + Project: testresources.Project1().Uuid, + ProjectName: testresources.Project1Invite().ProjectName, + }) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("Do you want to join project \"%s\" as %s? [Y/n] ✔ successfully joined project \"%s\"", + testresources.Project1Invite().ProjectName, + testresources.Project1Invite().Role.String(), + testresources.Project1Invite().ProjectName)), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_ListMembers(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceGetRequest, []apiv2.ProjectMember]{ + { + Name: "list project members", + CmdArgs: []string{"project", "member", "list", "--project", testresources.Project1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceGetRequest{ + Project: testresources.Project1().Uuid, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceGetResponse{ + Project: testresources.Project1(), + ProjectMembers: []*apiv2.ProjectMember{ + testresources.Project1Members(), testresources.Project2Members(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + ID ROLE INHERITED SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 PROJECT_ROLE_OWNER false now + 40c0da4b-9eb9-4371-91aa-1ae62193fa54 PROJECT_ROLE_EDITOR true now + `), + WantWideTable: new(` + ID ROLE INHERITED SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 PROJECT_ROLE_OWNER false now + 40c0da4b-9eb9-4371-91aa-1ae62193fa54 PROJECT_ROLE_EDITOR true now + `), + Template: new("{{ .id }} {{ .role }}"), + WantTemplate: new(` +16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 1 +40c0da4b-9eb9-4371-91aa-1ae62193fa54 2 + `), + WantMarkdown: new(` + | ID | ROLE | INHERITED | SINCE | + |--------------------------------------|---------------------|-----------|-------| + | 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 | PROJECT_ROLE_OWNER | false | now | + | 40c0da4b-9eb9-4371-91aa-1ae62193fa54 | PROJECT_ROLE_EDITOR | true | now | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_DeleteMember(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceRemoveMemberResponse, string]{ + { + Name: "delete project member", + CmdArgs: []string{"project", "member", "delete", testresources.Project1Members().Id, "--project", testresources.Project1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceRemoveMemberRequest{ + Project: testresources.Project1().Uuid, + Member: testresources.Project1Members().Id, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceRemoveMemberResponse{}) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("✔ successfully removed member \"%s\"", testresources.Project1Members().Id)), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_ProjectCmd_UpdateMember(t *testing.T) { + tests := []*e2e.Test[apiv2.ProjectServiceUpdateMemberResponse, *apiv2.ProjectMember]{ + { + Name: "update project member", + CmdArgs: []string{"project", "member", "update", testresources.Project1Members().Id, "--project", testresources.Project1().Uuid, "--role", testresources.Project1Members().Role.String()}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.ProjectServiceUpdateMemberRequest{ + Project: testresources.Project1().Uuid, + Member: testresources.Project1Members().Id, + Role: testresources.Project1Members().Role, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.ProjectServiceUpdateMemberResponse{ + ProjectMember: testresources.Project1Members(), + }) + }, + }, + }, + }), + WantObject: testresources.Project1Members(), + WantTable: new(` + ID ROLE INHERITED SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 PROJECT_ROLE_OWNER false now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/api/tenant_test.go b/tests/e2e/api/tenant_test.go index 7935e9b..ea5d4fc 100644 --- a/tests/e2e/api/tenant_test.go +++ b/tests/e2e/api/tenant_test.go @@ -1,14 +1,18 @@ package api_e2e import ( + "fmt" "testing" "connectrpc.com/connect" + "github.com/dustin/go-humanize" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" + "github.com/spf13/afero" + "github.com/stretchr/testify/require" ) func Test_TenantCmd_Describe(t *testing.T) { @@ -103,3 +107,547 @@ acme-corp ACME Corp tt.TestCmd(t) } } + +func Test_TenantCmd_Create(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceCreateResponse, *apiv2.Tenant]{ + { + Name: "create", + CmdArgs: []string{"tenant", "create", "--name", testresources.Tenant1().Name, "--description", testresources.Tenant1().Description, "--email", testresources.Tenant1().Email}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Description: &testresources.Tenant1().Description, + Name: testresources.Tenant1().Name, + Email: &testresources.Tenant1().Email, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceCreateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantObject: testresources.Tenant1(), + WantProtoObject: testresources.Tenant1(), + }, + { + Name: "create from file", + CmdArgs: append([]string{"tenant", "create"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Name: testresources.Tenant1().Name, + Description: &testresources.Tenant1().Description, + Email: &testresources.Tenant1().Email, + AvatarUrl: new(""), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceCreateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + `), + }, + { + Name: "create many from file", + CmdArgs: append([]string{"tenant", "create"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshalToMultiYAML(t, testresources.Tenant1(), testresources.Tenant2()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Name: testresources.Tenant1().Name, + Description: &testresources.Tenant1().Description, + AvatarUrl: new(""), + Email: &testresources.Tenant1().Email, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceCreateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Name: testresources.Tenant2().Name, + Description: &testresources.Tenant2().Description, + Email: &testresources.Tenant2().Email, + AvatarUrl: new(""), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceCreateResponse{ + Tenant: testresources.Tenant2(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + acme-corp ACME Corp admin@acme.io now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_Delete(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceDeleteResponse, *apiv2.Tenant]{ + { + Name: "delete", + CmdArgs: []string{"tenant", "delete", testresources.Tenant1().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceDeleteRequest{ + Login: testresources.Tenant1().Login, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceDeleteResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantObject: testresources.Tenant1(), + }, + { + Name: "delete from file", + CmdArgs: append([]string{"tenant", "delete"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceDeleteRequest{ + Login: testresources.Tenant1().Login, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceDeleteResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_Update(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceUpdateResponse, *apiv2.Tenant]{ + { + Name: "update", + CmdArgs: []string{"tenant", "update", testresources.Tenant1().Login, "--name", "new-name", "--description", "new-desc"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceUpdateRequest{ + Login: testresources.Tenant1().Login, + Name: new("new-name"), + Description: new("new-desc"), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceUpdateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantErr: fmt.Errorf("not implemented"), + }, + { + Name: "update from file", + CmdArgs: append([]string{"tenant", "update"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceUpdateRequest{ + Login: testresources.Tenant1().Login, + Name: new(testresources.Tenant1().Name), + Email: new(testresources.Tenant1().Email), + Description: new(testresources.Tenant1().Description), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceUpdateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_Apply(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceUpdateResponse, *apiv2.Tenant]{ + { + Name: "apply", + CmdArgs: append([]string{"tenant", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Email: new(testresources.Tenant1().Email), + Description: new(testresources.Tenant1().Description), + Name: testresources.Tenant1().Name, + AvatarUrl: new(""), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceCreateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + `), + }, + { + Name: "apply already exists", + CmdArgs: append([]string{"tenant", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceCreateRequest{ + Email: new(testresources.Tenant1().Email), + Description: new(testresources.Tenant1().Description), + Name: testresources.Tenant1().Name, + AvatarUrl: new(""), + }, + WantError: connect.NewError(connect.CodeAlreadyExists, fmt.Errorf("already exists")), + }, + { + WantRequest: &apiv2.TenantServiceUpdateRequest{ + Login: testresources.Tenant1().Login, + Email: new(testresources.Tenant1().Email), + Description: new(testresources.Tenant1().Description), + Name: new(testresources.Tenant1().Name), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceUpdateResponse{ + Tenant: testresources.Tenant1(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + ID NAME EMAIL REGISTERED + metal-stack Metal Stack info@metal-stack.io now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_ListMembers(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceGetRequest, []apiv2.TenantMember]{ + { + Name: "list tenant members", + CmdArgs: []string{"tenant", "member", "list", "--tenant", testresources.Tenant1().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceGetRequest{ + Login: testresources.Tenant1().Login, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceGetResponse{ + Tenant: testresources.Tenant1(), + TenantMembers: []*apiv2.TenantMember{ + testresources.Tenant1Members(), testresources.Tenant2Members(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + ID ROLE SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 TENANT_ROLE_OWNER now + 40c0da4b-9eb9-4371-91aa-1ae62193fa54 TENANT_ROLE_EDITOR now + `), + WantWideTable: new(` + ID ROLE SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 TENANT_ROLE_OWNER now + 40c0da4b-9eb9-4371-91aa-1ae62193fa54 TENANT_ROLE_EDITOR now + `), + Template: new("{{ .id }} {{ .role }} {{ .projects }}"), + WantTemplate: new(` +16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 1 [0d81bca7-73f6-4da3-8397-4a8c52a0c583 f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c] +40c0da4b-9eb9-4371-91aa-1ae62193fa54 2 [0d81bca7-73f6-4da3-8397-4a8c52a0c583] + `), + WantMarkdown: new(` + | ID | ROLE | SINCE | + |--------------------------------------|--------------------|-------| + | 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 | TENANT_ROLE_OWNER | now | + | 40c0da4b-9eb9-4371-91aa-1ae62193fa54 | TENANT_ROLE_EDITOR | now | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_DeleteMember(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceRemoveMemberResponse, string]{ + { + Name: "delete tenant member", + CmdArgs: []string{"tenant", "member", "remove", testresources.Tenant1Members().Id, "--tenant", testresources.Tenant1().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceRemoveMemberRequest{ + Login: testresources.Tenant1().Login, + Member: testresources.Tenant1Members().Id, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceRemoveMemberResponse{}) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("✔ successfully removed member \"%s\"", testresources.Tenant1Members().Id)), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_UpdateMember(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceUpdateMemberResponse, *apiv2.TenantMember]{ + { + Name: "update tenant member", + CmdArgs: []string{"tenant", "member", "update", testresources.Tenant1Members().Id, "--tenant", testresources.Tenant1().Login, "--role", testresources.Tenant1Members().Role.String()}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceUpdateMemberRequest{ + Login: testresources.Tenant1().Login, + Member: testresources.Tenant1Members().Id, + Role: testresources.Tenant1Members().Role, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceUpdateMemberResponse{ + TenantMember: testresources.Tenant1Members(), + }) + }, + }, + }, + }), + WantObject: testresources.Tenant1Members(), + WantTable: new(` + ID ROLE SINCE + 16d6e8ba-f574-494f-8d5e-74f6cb2d8db0 TENANT_ROLE_OWNER now + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_ListInvites(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceInvitesListResponse, apiv2.TenantInvite]{ + { + Name: "list invites", + CmdArgs: []string{"tenant", "invite", "list", "--tenant", testresources.Tenant2().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceInvitesListRequest{ + Login: testresources.Tenant2().Login, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceInvitesListResponse{ + Invites: []*apiv2.TenantInvite{ + testresources.Tenant1Invite(), + testresources.Tenant2Invite(), + }, + }) + }, + }, + }, + }), + WantTable: new(` + SECRET TENANT INVITED BY ROLE EXPIRES IN + secret acme-corp acme-corp TENANT_ROLE_EDITOR 2 days from now + secret metal-stack metal-stack TENANT_ROLE_VIEWER 2 days from now + `), + WantWideTable: new(` + SECRET TENANT INVITED BY ROLE EXPIRES IN + secret acme-corp acme-corp TENANT_ROLE_EDITOR 2 days from now + secret metal-stack metal-stack TENANT_ROLE_VIEWER 2 days from now + `), + Template: new("{{ .tenant }} {{ .role }}"), + WantTemplate: new(` +acme-corp 2 +metal-stack 3 + `), + WantMarkdown: new(` + | SECRET | TENANT | INVITED BY | ROLE | EXPIRES IN | + |--------|-------------|-------------|--------------------|-----------------| + | secret | acme-corp | acme-corp | TENANT_ROLE_EDITOR | 2 days from now | + | secret | metal-stack | metal-stack | TENANT_ROLE_VIEWER | 2 days from now | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_DeleteInvite(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceInviteDeleteResponse, string]{ + { + Name: "delete invite", + CmdArgs: []string{"tenant", "invite", "delete", testresources.Tenant1Invite().Secret, "--tenant", testresources.Tenant1().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceInviteDeleteRequest{ + Login: testresources.Tenant1().Login, + Secret: testresources.Tenant1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceInviteDeleteResponse{}) + }, + }, + }, + }), + WantMarkdown: new(""), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_CreateInvite(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceInviteRequest, string]{ + { + Name: "create invite", + CmdArgs: []string{"tenant", "invite", "generate-join-secret", "--role", testresources.Tenant1Invite().Role.String(), "--tenant", testresources.Tenant1().Login}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceInviteRequest{ + Login: testresources.Tenant1().Login, + Role: testresources.Tenant1Invite().Role, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceInviteResponse{ + Invite: testresources.Tenant1Invite(), + }) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("You can share this secret with the member to join, it expires in %s:\n\n%s (https://console.metal-stack.io/organization-invite/%s)", + humanize.RelTime(e2e.TimeBubbleStartTime(), testresources.Project1Invite().ExpiresAt.AsTime(), "from now", "ago"), + testresources.Project1Invite().Secret, + testresources.Project1Invite().Secret, + )), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TenantCmd_Join(t *testing.T) { + tests := []*e2e.Test[apiv2.TenantServiceInviteAcceptResponse, string]{ + { + Name: "join", + CmdArgs: []string{"tenant", "invite", "join", testresources.Tenant1Invite().Secret}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TenantServiceInviteGetRequest{ + Secret: testresources.Tenant1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceInviteGetResponse{ + Invite: testresources.Tenant1Invite(), + }) + }, + }, + { + WantRequest: &apiv2.TenantServiceInviteAcceptRequest{ + Secret: testresources.Tenant1Invite().Secret, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TenantServiceInviteAcceptResponse{ + Tenant: testresources.Tenant1().Login, + TenantName: testresources.Tenant1Invite().TargetTenantName, + }) + }, + }, + }, + }), + WantDefault: new(fmt.Sprintf("Do you want to join tenant \"%s\" as %s? [Y/n] ✔ successfully joined tenant \"%s\"", + testresources.Tenant1Invite().TenantName, + testresources.Tenant1Invite().Role.String(), + testresources.Tenant1Invite().TenantName)), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/api/token_test.go b/tests/e2e/api/token_test.go index 77ad210..19a9509 100644 --- a/tests/e2e/api/token_test.go +++ b/tests/e2e/api/token_test.go @@ -1,6 +1,7 @@ package api_e2e import ( + "fmt" "testing" "connectrpc.com/connect" @@ -9,6 +10,9 @@ import ( e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" + "github.com/spf13/afero" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/durationpb" ) func Test_TokenCmd_Describe(t *testing.T) { @@ -77,14 +81,14 @@ func Test_TokenCmd_List(t *testing.T) { }, }), WantTable: new(` - TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES - TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) - TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 0 2000-01-03 00:00:00 UTC (in 2d) + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) + TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 2 2000-01-03 00:00:00 UTC (in 2d) `), WantWideTable: new(` - TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES - TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) - TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 0 2000-01-03 00:00:00 UTC (in 2d) + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) + TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 2 2000-01-03 00:00:00 UTC (in 2d) `), Template: new("{{ .uuid }} {{ .description }}"), WantTemplate: new(` @@ -92,12 +96,237 @@ a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 ci token b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev token `), WantMarkdown: new(` - | TYPE | ID | ADMIN | USER | DESCRIPTION | ROLES | PERMS | EXPIRES | - |----------------|--------------------------------------|-------|----------------------|-------------|-------|-------|---------------------------------| - | TOKEN_TYPE_API | a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 | | admin@metal-stack.io | ci token | 0 | 0 | 2000-01-02 00:00:00 UTC (in 1d) | - | TOKEN_TYPE_API | b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 | | dev@metal-stack.io | dev token | 0 | 0 | 2000-01-03 00:00:00 UTC (in 2d) | + | TYPE | ID | ADMIN | USER | DESCRIPTION | ROLES | PERMS | EXPIRES | + |----------------|--------------------------------------|-------|----------------------|-------------|-------|-------|---------------------------------| + | TOKEN_TYPE_API | a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 | | admin@metal-stack.io | ci token | 0 | 0 | 2000-01-02 00:00:00 UTC (in 1d) | + | TOKEN_TYPE_API | b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 | | dev@metal-stack.io | dev token | 0 | 2 | 2000-01-03 00:00:00 UTC (in 2d) | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TokenCmd_Delete(t *testing.T) { + tests := []*e2e.Test[apiv2.TokenServiceRevokeResponse, *apiv2.Token]{ + { + Name: "delete", + CmdArgs: []string{"token", "delete", testresources.Token1().Uuid}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceRevokeRequest{ + Uuid: testresources.Token1().Uuid, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceRevokeResponse{}) + }, + }, + }, + }), + WantObject: &apiv2.Token{Uuid: testresources.Token1().Uuid}, + }, + { + Name: "delete from file", + CmdArgs: append([]string{"token", "delete"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceRevokeRequest{ + Uuid: testresources.Token1().Uuid, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceRevokeResponse{}) + }, + }, + }, + }, + ), + WantTable: new(` + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_UNSPECIFIED a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 0 0 1970-01-01 00:00:00 UTC (in -10957d) + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TokenCmd_Create(t *testing.T) { + tests := []*e2e.Test[apiv2.TokenServiceGetResponse, *apiv2.Token]{ + { + Name: "create", + CmdArgs: []string{"token", "create", "--description", testresources.Token1().Description, "--expires", durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())).AsDuration().String()}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceCreateRequest{ + Description: testresources.Token1().Description, + Expires: durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceCreateResponse{ + Token: testresources.Token1(), + Secret: "token-secret", + }) + }, + }, + }, + }), + WantMarkdown: new(` + Make sure to copy your personal access token now as you will not be able to see this again. + + token-secret + + | TYPE | ID | ADMIN | USER | DESCRIPTION | ROLES | PERMS | EXPIRES | + |----------------|--------------------------------------|-------|----------------------|-------------|-------|-------|---------------------------------| + | TOKEN_TYPE_API | a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 | | admin@metal-stack.io | ci token | 0 | 0 | 2000-01-02 00:00:00 UTC (in 1d) | + `), + }, + { + Name: "create from file", + CmdArgs: append([]string{"token", "create"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceCreateRequest{ + Description: testresources.Token1().Description, + Expires: durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())), + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceCreateResponse{ + Token: testresources.Token1(), + Secret: "token-secret", + }) + }, + }, + }, + }), + WantTable: new(` + Make sure to copy your personal access token now as you will not be able to see this again. + + token-secret + + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_UpdateCmd_Update(t *testing.T) { + tests := []*e2e.Test[apiv2.TokenServiceUpdateResponse, *apiv2.Token]{ + { + Name: "update from file", + CmdArgs: append([]string{"token", "update"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token2()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceUpdateRequest{ + Uuid: testresources.Token2().Uuid, + Description: new(testresources.Token2().Description), + Permissions: testresources.Token2().Permissions, + ProjectRoles: testresources.Token2().ProjectRoles, + TenantRoles: testresources.Token2().TenantRoles, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceUpdateResponse{ + Token: testresources.Token2(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 dev@metal-stack.io dev token 0 2 2000-01-03 00:00:00 UTC (in 2d) + `), + Template: new("{{ .uuid }} {{ .permissions }}"), + WantTemplate: new(`b4c2e7f3-5a9d-4b8e-a1c3-2d6f9e4b8a01 [map[methods:[api/method1 api/method2] subject:0d81bca7-73f6-4da3-8397-4a8c52a0c583] map[methods:[api/method3] subject:metal-stack]]`), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} + +func Test_TokenCmd_Apply(t *testing.T) { + tests := []*e2e.Test[apiv2.TokenServiceUpdateResponse, *apiv2.Token]{ + { + Name: "apply", + CmdArgs: append([]string{"token", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceCreateRequest{ + Description: testresources.Token1().Description, + Labels: testresources.Token1().Meta.Labels, + Expires: durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())), + Permissions: testresources.Token1().Permissions, + }, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.TokenServiceCreateResponse{ + Token: testresources.Token1(), + }) + }, + }, + }, + }, + ), + WantTable: new(` + Make sure to copy your personal access token now as you will not be able to see this again. + + + + TYPE ID ADMIN USER DESCRIPTION ROLES PERMS EXPIRES + TOKEN_TYPE_API a3b1f6d2-4e8c-4f7a-9d2e-1b5c8f3a7e90 admin@metal-stack.io ci token 0 0 2000-01-02 00:00:00 UTC (in 1d) `), }, + { + Name: "apply already exists", + CmdArgs: append([]string{"token", "apply"}, e2e.AppendFromFileCommonArgs()...), + NewRootCmd: e2e.NewRootCmd(t, + &e2e.TestConfig{ + FsMocks: func(fs *afero.Afero) { + require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) + }, + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.TokenServiceCreateRequest{ + Description: testresources.Token1().Description, + Labels: testresources.Token1().Meta.Labels, + Expires: durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())), + Permissions: testresources.Token1().Permissions, + }, + WantError: connect.NewError(connect.CodeAlreadyExists, fmt.Errorf("already_exists")), + }, + }, + }, + ), + WantErr: fmt.Errorf("error creating entity: already_exists: already_exists"), + }, } for _, tt := range tests { tt.TestCmd(t) diff --git a/tests/e2e/api/user_test.go b/tests/e2e/api/user_test.go new file mode 100644 index 0000000..50a4792 --- /dev/null +++ b/tests/e2e/api/user_test.go @@ -0,0 +1,50 @@ +package api_e2e + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/metal-stack/api/go/client" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" +) + +func Test_UserCmd_Describe(t *testing.T) { + tests := []*e2e.Test[apiv2.UserServiceGetResponse, *apiv2.User]{ + { + Name: "describe", + CmdArgs: []string{"user", "describe"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.UserServiceGetRequest{}, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.UserServiceGetResponse{ + User: testresources.User(), + }) + }, + }, + }, + }), + WantObject: testresources.User(), + WantProtoObject: testresources.User(), + WantTable: new(` + LOGIN NAME EMAIL + larry@metal-stack.io@openid-connect Larry larry@metal-stack.io + `), + WantWideTable: new(` + LOGIN NAME EMAIL TENANTS PROJECTS + larry@metal-stack.io@openid-connect Larry larry@metal-stack.io Metal Stack, ACME Corp project-a, project-b + `), + WantMarkdown: new(` + | LOGIN | NAME | EMAIL | + |-------------------------------------|-------|----------------------| + | larry@metal-stack.io@openid-connect | Larry | larry@metal-stack.io | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/api/version_test.go b/tests/e2e/api/version_test.go new file mode 100644 index 0000000..0915934 --- /dev/null +++ b/tests/e2e/api/version_test.go @@ -0,0 +1,37 @@ +package api_e2e + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/metal-stack/api/go/client" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/cli/tests/e2e/testresources" +) + +func Test_VersionCmd(t *testing.T) { + tests := []*e2e.Test[apiv2.VersionServiceGetResponse, *apiv2.Version]{ + { + Name: "describe", + CmdArgs: []string{"version"}, + NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + ClientCalls: []client.ClientCall{ + { + WantRequest: &apiv2.VersionServiceGetRequest{}, + WantResponse: func() connect.AnyResponse { + return connect.NewResponse(&apiv2.VersionServiceGetResponse{ + Version: testresources.Version(), + }) + }, + }, + }, + }), + Template: new("{{ .Server.build_date }} {{ .Server.git_sha1 }} {{ .Server.revision }} {{ .Server.version }}"), + WantTemplate: new(`2026-03-21T15:35:07+00:00 477edc0b tags/v0.1.8-0-g476edc0 v0.1.8`), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/tests/e2e/testresources/audit.go b/tests/e2e/testresources/audit.go new file mode 100644 index 0000000..dd6968b --- /dev/null +++ b/tests/e2e/testresources/audit.go @@ -0,0 +1,53 @@ +package testresources + +import ( + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + Trace1 = func() *apiv2.AuditTrace { + return &apiv2.AuditTrace{ + Uuid: "d1ff7267-2fbb-4a63-a7c1-44f1a83381a7", + Timestamp: timestamppb.New(e2e.TimeBubbleStartTime()), + User: "me", + Tenant: "a", + Project: new(Project1().Uuid), + Method: "/apiv2.Create/", + Body: new("request body"), + SourceIp: "1.2.3.4", + Phase: apiv2.AuditPhase_AUDIT_PHASE_REQUEST, + } + } + + Trace2 = func() *apiv2.AuditTrace { + return &apiv2.AuditTrace{ + Uuid: "d1ff7267-2fbb-4a63-a7c1-44f1a83381a7", + Timestamp: timestamppb.New(e2e.TimeBubbleStartTime()), + User: "me", + Tenant: "a", + Project: new(Project1().Uuid), + Method: "/apiv2.List/", + Body: new("result body"), + SourceIp: "1.2.3.4", + ResultCode: new(int32(codes.AlreadyExists)), + Phase: apiv2.AuditPhase_AUDIT_PHASE_RESPONSE, + } + } + + Trace3 = func() *apiv2.AuditTrace { + return &apiv2.AuditTrace{ + Uuid: "5091c4e9-e8db-483c-ab6b-fe14f82570a7", + Timestamp: timestamppb.New(e2e.TimeBubbleStartTime().AddDate(1, 0, 0)), + User: "Larry", + Tenant: "b", + Project: new(Project1().Uuid), + Method: "/apiv2.List/", + Body: new("result body"), + SourceIp: "1.2.3.4", + Phase: apiv2.AuditPhase_AUDIT_PHASE_REQUEST, + } + } +) diff --git a/tests/e2e/testresources/component.go b/tests/e2e/testresources/component.go new file mode 100644 index 0000000..34988b4 --- /dev/null +++ b/tests/e2e/testresources/component.go @@ -0,0 +1,47 @@ +package testresources + +import ( + "time" + + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + Component1 = func() *apiv2.Component { + return &apiv2.Component{ + Uuid: "c1a2b3d4-e5f6-7890-abcd-ef1234567890", + Type: apiv2.ComponentType_COMPONENT_TYPE_METAL_CORE, + Identifier: "metal-core-1", + StartedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + ReportedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + Interval: durationpb.New(10 * time.Second), + Version: &apiv2.Version{ + Version: "v1.0.0", + }, + Token: &apiv2.Token{ + Uuid: "t1a2b3d4-e5f6-7890-abcd-ef1234567890", + Expires: timestamppb.New(e2e.TimeBubbleStartTime().Add(24 * time.Hour)), + }, + } + } + Component2 = func() *apiv2.Component { + return &apiv2.Component{ + Uuid: "d2b3c4e5-f6a7-8901-bcde-f12345678901", + Type: apiv2.ComponentType_COMPONENT_TYPE_PIXIECORE, + Identifier: "pixiecore-1", + StartedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + ReportedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + Interval: durationpb.New(10 * time.Second), + Version: &apiv2.Version{ + Version: "v2.0.0", + }, + Token: &apiv2.Token{ + Uuid: "t2b3c4e5-f6a7-8901-bcde-f12345678901", + Expires: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), + }, + } + } +) diff --git a/tests/e2e/testresources/images.go b/tests/e2e/testresources/images.go index 6adff27..150aaab 100644 --- a/tests/e2e/testresources/images.go +++ b/tests/e2e/testresources/images.go @@ -10,6 +10,7 @@ var ( Description: new("Ubuntu 24.04 LTS"), Features: []apiv2.ImageFeature{apiv2.ImageFeature_IMAGE_FEATURE_MACHINE}, Classification: apiv2.ImageClassification_IMAGE_CLASSIFICATION_SUPPORTED, + Meta: &apiv2.Meta{}, } } Image2 = func() *apiv2.Image { @@ -19,6 +20,7 @@ var ( Description: new("Metal Firewall"), Features: []apiv2.ImageFeature{apiv2.ImageFeature_IMAGE_FEATURE_FIREWALL}, Classification: apiv2.ImageClassification_IMAGE_CLASSIFICATION_PREVIEW, + Meta: &apiv2.Meta{}, } } ) diff --git a/tests/e2e/testresources/projects.go b/tests/e2e/testresources/projects.go index c1c107e..4859fc1 100644 --- a/tests/e2e/testresources/projects.go +++ b/tests/e2e/testresources/projects.go @@ -1,6 +1,8 @@ package testresources import ( + "time" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" @@ -29,4 +31,44 @@ var ( }, } } + + Project1Invite = func() *apiv2.ProjectInvite { + return &apiv2.ProjectInvite{ + Secret: "secret", + Project: "0d81bca7-73f6-4da3-8397-4a8c52a0c583", + Role: apiv2.ProjectRole_PROJECT_ROLE_EDITOR, + Joined: false, + ProjectName: "project-a", + TenantName: "metal-stack", + ExpiresAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), + } + } + Project2Invite = func() *apiv2.ProjectInvite { + return &apiv2.ProjectInvite{ + Secret: "secret", + Project: "f3b4e6a1-2c8d-4e5f-a7b9-1d3e5f7a9b0c", + Role: apiv2.ProjectRole_PROJECT_ROLE_EDITOR, + Joined: false, + ProjectName: "project-b", + TenantName: "metal-stack", + ExpiresAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), + } + } + + Project1Members = func() *apiv2.ProjectMember { + return &apiv2.ProjectMember{ + Id: "16d6e8ba-f574-494f-8d5e-74f6cb2d8db0", + Role: apiv2.ProjectRole_PROJECT_ROLE_OWNER, + InheritedMembership: false, + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + } + } + Project2Members = func() *apiv2.ProjectMember { + return &apiv2.ProjectMember{ + Id: "40c0da4b-9eb9-4371-91aa-1ae62193fa54", + Role: apiv2.ProjectRole_PROJECT_ROLE_EDITOR, + InheritedMembership: true, + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + } + } ) diff --git a/tests/e2e/testresources/switch.go b/tests/e2e/testresources/switch.go new file mode 100644 index 0000000..408124c --- /dev/null +++ b/tests/e2e/testresources/switch.go @@ -0,0 +1,146 @@ +package testresources + +import ( + "time" + + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/cli/testing/e2e" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + Switch1 = func() *apiv2.Switch { + return &apiv2.Switch{ + Id: "leaf01", + Partition: "fra-equ01", + Rack: new("rack-1"), + Description: "leaf switch 1", + ManagementIp: "10.0.0.1", + ManagementUser: new("admin"), + MachineConnections: []*apiv2.MachineConnection{ + &apiv2.MachineConnection{ + MachineId: "id1", + Nic: Nic1(), + }, + }, + Nics: []*apiv2.SwitchNic{Nic1(), Nic2()}, + Os: &apiv2.SwitchOS{ + Vendor: apiv2.SwitchOSVendor_SWITCH_OS_VENDOR_SONIC, + Version: "4.2.0", + MetalCoreVersion: "v0.9.1 (abc1234), tags/v0.9.1", + }, + LastSync: &apiv2.SwitchSync{ + Time: timestamppb.New(e2e.TimeBubbleStartTime()), + Duration: durationpb.New(100 * time.Millisecond), + }, + Meta: &apiv2.Meta{ + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + }, + } + } + Switch2 = func() *apiv2.Switch { + return &apiv2.Switch{ + Id: "leaf02", + Partition: "fra-equ01", + Rack: new("rack-1"), + Description: "leaf switch 2", + ManagementIp: "10.0.0.2", + ManagementUser: new("admin"), + Os: &apiv2.SwitchOS{ + Vendor: apiv2.SwitchOSVendor_SWITCH_OS_VENDOR_SONIC, + Version: "4.2.0", + MetalCoreVersion: "v0.9.1 (abc1234), tags/v0.9.1", + }, + LastSync: &apiv2.SwitchSync{ + Time: timestamppb.New(e2e.TimeBubbleStartTime()), + Duration: durationpb.New(200 * time.Millisecond), + }, + Meta: &apiv2.Meta{ + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + }, + } + } + + Nic1 = func() *apiv2.SwitchNic { + return &apiv2.SwitchNic{ + Name: "Ethernet0", + Identifier: "oid:0x1000000000001", + Mac: "52:54:00:ab:cd:01", + Vrf: new("default"), + State: &apiv2.NicState{ + Desired: new(apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_UP), + Actual: apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_UP, + }, + BgpFilter: &apiv2.BGPFilter{ + Cidrs: []string{ + "10.0.0.0/24", + "192.168.100.0/24", + }, + Vnis: []string{ + "10001", + "10002", + }, + }, + BgpPortState: &apiv2.SwitchBGPPortState{ + Neighbor: "10.0.0.2", + PeerGroup: "TOR-LEAFS", + VrfName: "default", + BgpState: apiv2.BGPState_BGP_STATE_ESTABLISHED, + BgpTimerUpEstablished: timestamppb.New(time.Now().Add(-2 * time.Hour)), + SentPrefixCounter: 120, + AcceptedPrefixCounter: 118, + }, + } + } + Nic2 = func() *apiv2.SwitchNic { + return &apiv2.SwitchNic{ + Name: "Ethernet4", + Identifier: "oid:0x1000000000002", + Mac: "52:54:00:ab:cd:02", + State: &apiv2.NicState{ + Desired: new(apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_UP), + Actual: apiv2.SwitchPortStatus_SWITCH_PORT_STATUS_DOWN, + }, + BgpFilter: &apiv2.BGPFilter{ + Cidrs: []string{"10.1.0.0/24"}, + Vnis: []string{"20001"}, + }, + BgpPortState: &apiv2.SwitchBGPPortState{ + Neighbor: "10.1.0.2", + PeerGroup: "TOR-LEAFS", + VrfName: "default", + BgpState: apiv2.BGPState_BGP_STATE_IDLE, + BgpTimerUpEstablished: nil, + SentPrefixCounter: 0, + AcceptedPrefixCounter: 0, + }, + } + } + SwitchWithMachines1 = func() *apiv2.SwitchWithMachines { + return &apiv2.SwitchWithMachines{ + Id: Switch1().Id, + Partition: Switch1().Partition, + Rack: *Switch1().Rack, + Connections: []*apiv2.SwitchNicWithMachine{ + { + Nic: Switch1().Nics[0], + Machine: &apiv2.Machine{ + Uuid: "id1", + Partition: &apiv2.Partition{ + Id: Switch1().Partition, + }, + Rack: *Switch1().Rack, + Size: &apiv2.Size{ + Id: "m1-small", + }, + }, + Fru: &apiv2.MachineFRU{ + ProductSerial: new("ps-1"), + ChassisPartSerial: new("cs-1"), + }, + }, + }, + } + } +) diff --git a/tests/e2e/testresources/tasks.go b/tests/e2e/testresources/tasks.go new file mode 100644 index 0000000..1c6cbc2 --- /dev/null +++ b/tests/e2e/testresources/tasks.go @@ -0,0 +1,68 @@ +package testresources + +import ( + "time" + + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/cli/testing/e2e" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + Task1 = func() *adminv2.TaskInfo { + return &adminv2.TaskInfo{ + Id: "00dc6a98-bd80-787a-9725-ffb692d83261", + Queue: "default", + Type: "image-provision", + Payload: []byte(`{"machine_id":"machine1"}`), + State: adminv2.TaskState_TASK_STATE_ACTIVE, + MaxRetry: 3, + Retried: 1, + LastError: "connection timeout", + LastFailedAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(-5 * time.Minute)), + Timeout: durationpb.New(30 * time.Second), + Deadline: timestamppb.New(e2e.TimeBubbleStartTime().Add(5 * time.Minute)), + NextProcessAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(10 * time.Second)), + Retention: durationpb.New(24 * time.Hour), + CompletedAt: nil, + } + } + Task2 = func() *adminv2.TaskInfo { + return &adminv2.TaskInfo{ + Id: "00dc6ab4-34c0-73ce-af77-3e07748d0e0d", + Queue: "default", + Type: "firewall-update", + Payload: []byte(`{"firewall_id":"fw1"}`), + State: adminv2.TaskState_TASK_STATE_PENDING, + MaxRetry: 5, + Retried: 0, + LastError: "", + LastFailedAt: nil, + Timeout: durationpb.New(60 * time.Second), + Deadline: timestamppb.New(e2e.TimeBubbleStartTime().Add(10 * time.Minute)), + NextProcessAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(2 * time.Second)), + Retention: durationpb.New(48 * time.Hour), + CompletedAt: nil, + } + } + Task3 = func() *adminv2.TaskInfo { + return &adminv2.TaskInfo{ + Id: "00dc6ab5-1f20-7426-a397-8644fb78324e", + Queue: "high-priority", + Type: "machine-reimage", + Payload: []byte(`{"machine_id":"machine2"}`), + State: adminv2.TaskState_TASK_STATE_COMPLETED, + MaxRetry: 3, + Retried: 0, + LastError: "", + LastFailedAt: nil, + Timeout: durationpb.New(5 * time.Minute), + Deadline: timestamppb.New(e2e.TimeBubbleStartTime().Add(30 * time.Minute)), + NextProcessAt: nil, + Retention: durationpb.New(7 * 24 * time.Hour), + CompletedAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(-10 * time.Minute)), + Result: []byte(`success`), + } + } +) diff --git a/tests/e2e/testresources/tenants.go b/tests/e2e/testresources/tenants.go index 9226681..1665bac 100644 --- a/tests/e2e/testresources/tenants.go +++ b/tests/e2e/testresources/tenants.go @@ -1,6 +1,8 @@ package testresources import ( + "time" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" @@ -29,4 +31,46 @@ var ( }, } } + + Tenant1Invite = func() *apiv2.TenantInvite { + return &apiv2.TenantInvite{ + Secret: "secret", + TargetTenant: "metal-stack", + TargetTenantName: "Metal Stack", + Role: apiv2.TenantRole_TENANT_ROLE_VIEWER, + Joined: false, + Tenant: "metal-stack", + TenantName: "Metal Stack", + ExpiresAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), + } + } + Tenant2Invite = func() *apiv2.TenantInvite { + return &apiv2.TenantInvite{ + Secret: "secret", + TargetTenant: "acme-corp", + TargetTenantName: "ACME Corp", + Role: apiv2.TenantRole_TENANT_ROLE_EDITOR, + Joined: false, + Tenant: "acme-corp", + TenantName: "ACME Corp", + ExpiresAt: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), + } + } + + Tenant1Members = func() *apiv2.TenantMember { + return &apiv2.TenantMember{ + Id: "16d6e8ba-f574-494f-8d5e-74f6cb2d8db0", + Role: apiv2.TenantRole_TENANT_ROLE_OWNER, + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + Projects: []string{Project1().Uuid, Project2().Uuid}, + } + } + Tenant2Members = func() *apiv2.TenantMember { + return &apiv2.TenantMember{ + Id: "40c0da4b-9eb9-4371-91aa-1ae62193fa54", + Role: apiv2.TenantRole_TENANT_ROLE_EDITOR, + CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), + Projects: []string{Project1().Uuid}, + } + } ) diff --git a/tests/e2e/testresources/tokens.go b/tests/e2e/testresources/tokens.go index fcfa890..35f8dae 100644 --- a/tests/e2e/testresources/tokens.go +++ b/tests/e2e/testresources/tokens.go @@ -31,7 +31,16 @@ var ( TokenType: apiv2.TokenType_TOKEN_TYPE_API, Expires: timestamppb.New(e2e.TimeBubbleStartTime().Add(48 * time.Hour)), IssuedAt: timestamppb.New(e2e.TimeBubbleStartTime()), - Permissions: nil, + Permissions: []*apiv2.MethodPermission{ + &apiv2.MethodPermission{ + Subject: Project1().Uuid, + Methods: []string{"api/method1", "api/method2"}, + }, + &apiv2.MethodPermission{ + Subject: Tenant1().Login, + Methods: []string{"api/method3"}, + }, + }, Meta: &apiv2.Meta{ CreatedAt: timestamppb.New(e2e.TimeBubbleStartTime()), }, diff --git a/tests/e2e/testresources/user.go b/tests/e2e/testresources/user.go new file mode 100644 index 0000000..52f8734 --- /dev/null +++ b/tests/e2e/testresources/user.go @@ -0,0 +1,17 @@ +package testresources + +import apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + +var ( + User = func() *apiv2.User { + return &apiv2.User{ + Name: "Larry", + Email: "larry@metal-stack.io", + Login: "larry@metal-stack.io@openid-connect", + AvatarUrl: "", + DefaultTenant: Tenant1(), + Tenants: []*apiv2.Tenant{Tenant1(), Tenant2()}, + Projects: []*apiv2.Project{Project1(), Project2()}, + } + } +) diff --git a/tests/e2e/testresources/version.go b/tests/e2e/testresources/version.go new file mode 100644 index 0000000..48e3761 --- /dev/null +++ b/tests/e2e/testresources/version.go @@ -0,0 +1,14 @@ +package testresources + +import apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + +var ( + Version = func() *apiv2.Version { + return &apiv2.Version{ + Version: "v0.1.8", + Revision: "tags/v0.1.8-0-g476edc0", + GitSha1: "477edc0b", + BuildDate: "2026-03-21T15:35:07+00:00", + } + } +) From 3296587b5104f25a25f0077e5e138b7be2dbc4e2 Mon Sep 17 00:00:00 2001 From: Anna Schreiner Date: Wed, 3 Jun 2026 11:49:08 +0200 Subject: [PATCH 3/3] fix test --- go.mod | 24 ++--------------- go.sum | 39 ++-------------------------- tests/e2e/admin/audit_test.go | 7 ++--- tests/e2e/admin/image_test.go | 17 ++++++------ tests/e2e/admin/switch_test.go | 16 ++++++------ tests/e2e/admin/task_test.go | 13 +++++----- tests/e2e/api/audit_test.go | 4 +-- tests/e2e/api/image_test.go | 2 +- tests/e2e/api/project_test.go | 22 ++++++++-------- tests/e2e/api/tenant_test.go | 36 ++++++++++++------------- tests/e2e/api/token_test.go | 24 ++++++++--------- tests/e2e/api/user_test.go | 5 ++-- tests/e2e/api/version_test.go | 5 ++-- tests/e2e/testresources/audit.go | 2 +- tests/e2e/testresources/component.go | 2 +- tests/e2e/testresources/switch.go | 2 +- tests/e2e/testresources/tasks.go | 2 +- tests/e2e/testresources/tenants.go | 2 +- tests/e2e/testresources/tokens.go | 2 +- 19 files changed, 88 insertions(+), 138 deletions(-) diff --git a/go.mod b/go.mod index 28b8d0b..8471386 100644 --- a/go.mod +++ b/go.mod @@ -3,49 +3,29 @@ module github.com/metal-stack/cli go 1.26 require ( -<<<<<<< HEAD - connectrpc.com/connect v1.19.1 -======= - buf.build/go/protoyaml v0.7.0 connectrpc.com/connect v1.20.0 ->>>>>>> main connectrpc.com/validate v0.6.0 github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.19.0 github.com/google/go-cmp v0.7.0 -<<<<<<< HEAD - github.com/metal-stack/api v0.0.58 - github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f -======= github.com/google/uuid v1.6.0 github.com/metal-stack/api v0.1.0 - github.com/metal-stack/metal-lib v0.25.1 ->>>>>>> main + github.com/metal-stack/metal-lib v0.25.2-0.20260603093551-911f9ac795eb github.com/metal-stack/v v1.0.3 github.com/spf13/afero v1.15.0 github.com/spf13/cobra v1.10.2 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 -<<<<<<< HEAD - google.golang.org/grpc v1.79.3 -======= google.golang.org/grpc v1.81.1 ->>>>>>> main google.golang.org/protobuf v1.36.11 sigs.k8s.io/yaml v1.6.0 ) require ( -<<<<<<< HEAD - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect - buf.build/go/protovalidate v1.1.3 // indirect - buf.build/go/protoyaml v0.6.0 // indirect - cel.dev/expr v0.25.1 // indirect -======= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect buf.build/go/protovalidate v1.2.0 // indirect + buf.build/go/protoyaml v0.7.0 // indirect cel.dev/expr v0.25.2 // indirect ->>>>>>> main github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/displaywidth v0.10.0 // indirect diff --git a/go.sum b/go.sum index e31b7da..e909a5f 100644 --- a/go.sum +++ b/go.sum @@ -69,17 +69,10 @@ github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLG github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -<<<<<<< HEAD -github.com/metal-stack/api v0.0.58 h1:7UxnZrM41BS0f4S9RvqDg0/YTvs3FveawuyBoKz9WhA= -github.com/metal-stack/api v0.0.58/go.mod h1:hEgtKVD7UnUwUExdA7pbFvVRxNRxSGUnU+bZce46//c= -github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f h1:qTEfCIrCsE8YTSIhMiI2jYlDqO20K3S4pCNkB9wB3vQ= -github.com/metal-stack/metal-lib v0.24.2-0.20260324151418-0917620d251f/go.mod h1:u1wQl98JOfzyXqY7+0qD2xFSMnxvzCykkLgW80U1IrA= -======= github.com/metal-stack/api v0.1.0 h1:V3nrarxGexnE0f1/2UtGCIAtjP815p7+yqQvruD0KJQ= github.com/metal-stack/api v0.1.0/go.mod h1:wFU5aKfuurbBISQSIdJwBLQf4mTOBlERqWBzCafahEY= -github.com/metal-stack/metal-lib v0.25.1 h1:z14xNl59ueQavNvMG4wcIZGqVyosNlaNFcy8hUu3SCU= -github.com/metal-stack/metal-lib v0.25.1/go.mod h1:FWviUPM7oH1CnmCwkyLjWpd3yuzf6NnR97Xf45P2/Fk= ->>>>>>> main +github.com/metal-stack/metal-lib v0.25.2-0.20260603093551-911f9ac795eb h1:xxuBj37RFfju4jj+0GEks3DMU+1h8T4cUQnlk1ROxH8= +github.com/metal-stack/metal-lib v0.25.2-0.20260603093551-911f9ac795eb/go.mod h1:tnx4MM5oml10EMN6Nq6oFSbjOKB9B27WUZQUyZ4MywA= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/minio/minlz v1.1.1 h1:OGmft1V6AnI/Wme332U6bhG54nxEan+VFgkD7lat4KM= @@ -128,48 +121,20 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -<<<<<<< HEAD -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= -google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 h1:CogIeEXn4qWYzzQU0QqvYBM8yDF9cFYzDq9ojSpv0Js= -google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= -======= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68 h1:WVVw1Nl19li0fMX++FJ3ye1z9+S1N35QODDy5qpnaXw= -google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:1dCETSCY2YKZNXQE3h4fun3TYwF5p8jejRKZgfWAgAY= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68 h1:PvEgGJf9C/1u5CHkInMg7UFYYUoiaQmW2LbtH0pjB78= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= ->>>>>>> main google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/tests/e2e/admin/audit_test.go b/tests/e2e/admin/audit_test.go index 847dafa..9071842 100644 --- a/tests/e2e/admin/audit_test.go +++ b/tests/e2e/admin/audit_test.go @@ -7,8 +7,9 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_AdminAuditCmd_List(t *testing.T) { @@ -16,7 +17,7 @@ func Test_AdminAuditCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "audit", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.AuditServiceListRequest{ @@ -70,7 +71,7 @@ func Test_AuditCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"admin", "audit", "describe", testresources.Trace1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.AuditServiceGetRequest{ diff --git a/tests/e2e/admin/image_test.go b/tests/e2e/admin/image_test.go index f8349ae..ec2ed42 100644 --- a/tests/e2e/admin/image_test.go +++ b/tests/e2e/admin/image_test.go @@ -7,8 +7,9 @@ import ( "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) @@ -18,7 +19,7 @@ func Test_AdminImageCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"admin", "image", "delete", testresources.Image1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ImageServiceDeleteRequest{ @@ -69,7 +70,7 @@ func Test_AdminImageCmd_Create(t *testing.T) { "--classification", "supported", "--description", *testresources.Image1().Description, "--name", *testresources.Image1().Name}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ImageServiceCreateRequest{ @@ -92,8 +93,8 @@ func Test_AdminImageCmd_Create(t *testing.T) { { Name: "create from file", CmdArgs: append([]string{"admin", "image", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Image1()), 0755)) }, @@ -139,7 +140,7 @@ func Test_AdminImageCmd_Update(t *testing.T) { { Name: "update", CmdArgs: []string{"admin", "image", "update", testresources.Image1().Id, "--name", *testresources.Image1().Name}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.ImageServiceUpdateRequest{ @@ -166,8 +167,8 @@ func Test_AdminImageCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"admin", "image", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Image1()), 0755)) }, diff --git a/tests/e2e/admin/switch_test.go b/tests/e2e/admin/switch_test.go index 368d12a..10c13b0 100644 --- a/tests/e2e/admin/switch_test.go +++ b/tests/e2e/admin/switch_test.go @@ -18,7 +18,7 @@ func Test_AdminSwitchCmd_Describe(t *testing.T) { tests := []*e2e.Test[adminv2.SwitchServiceGetResponse, *apiv2.Switch]{ { Name: "describe", - CmdArgs: []string{"admin", "switch", "describe", testresources.Switch2()}, + CmdArgs: []string{"admin", "switch", "describe", testresources.Switch2().Id}, NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { @@ -143,8 +143,8 @@ func Test_AdminSwitchCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"admin", "switch", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Switch2()), 0755)) }, @@ -193,7 +193,7 @@ func Test_AdminSwitchCmd_ConnectedMachines(t *testing.T) { { Name: "connected machines", CmdArgs: []string{"admin", "switch", "connected-machines"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceConnectedMachinesRequest{ @@ -225,7 +225,7 @@ func Test_AdminSwitchCmd_Detail(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "switch", "detail", testresources.Switch1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceListRequest{ @@ -268,7 +268,7 @@ func Test_AdminSwitchCmd_Migrate(t *testing.T) { { Name: "describe", CmdArgs: []string{"admin", "switch", "migrate", testresources.Switch1().Id, testresources.Switch2().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServiceMigrateRequest{ @@ -313,7 +313,7 @@ func Test_AdminSwitchCmd_Port(t *testing.T) { { Name: "port up", CmdArgs: []string{"admin", "switch", "port", "up", testresources.Switch1().Id, "--port", testresources.Nic1().Name}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServicePortRequest{ @@ -388,7 +388,7 @@ Desired: { Name: "down", CmdArgs: []string{"admin", "switch", "port", "down", testresources.Switch1().Id, "--port", testresources.Nic1().Name}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.SwitchServicePortRequest{ diff --git a/tests/e2e/admin/task_test.go b/tests/e2e/admin/task_test.go index d8194fe..2137989 100644 --- a/tests/e2e/admin/task_test.go +++ b/tests/e2e/admin/task_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_AdminTaskCmd_List(t *testing.T) { @@ -15,7 +16,7 @@ func Test_AdminTaskCmd_List(t *testing.T) { { Name: "list", CmdArgs: []string{"admin", "task", "list"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TaskServiceListRequest{}, @@ -55,7 +56,7 @@ func Test_AdminTaskCmd_List(t *testing.T) { { Name: "list with queue filter", CmdArgs: []string{"admin", "task", "list", "--queue", "high-priority"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TaskServiceListRequest{ @@ -87,7 +88,7 @@ func Test_AdminTaskCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"admin", "task", "describe", testresources.Task1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TaskServiceGetRequest{ @@ -112,7 +113,7 @@ func Test_AdminTaskCmd_Describe(t *testing.T) { { Name: "describe with queue", CmdArgs: []string{"admin", "task", "describe", testresources.Task3().Id, "--queue", "high-priority"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TaskServiceGetRequest{ @@ -158,7 +159,7 @@ func Test_AdminTaskQueuesCmd(t *testing.T) { { Name: "queues", CmdArgs: []string{"admin", "task", "queues"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &adminv2.TaskServiceQueuesRequest{}, diff --git a/tests/e2e/api/audit_test.go b/tests/e2e/api/audit_test.go index fd7b976..9b0e492 100644 --- a/tests/e2e/api/audit_test.go +++ b/tests/e2e/api/audit_test.go @@ -60,7 +60,7 @@ d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 2`), { Name: "list", CmdArgs: []string{"audit", "list", "--tenant", testresources.Trace3().Tenant, "--from", timestamppb.New(time.Date(2000, 12, 24, 0, 0, 0, 0, time.UTC)).AsTime().Format("2006-01-02 15:04:05"), "--to", timestamppb.New(time.Date(2001, 1, 2, 0, 0, 0, 0, time.UTC)).AsTime().Format("2006-01-02 15:04:05"), "--user", testresources.Trace3().User}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceListRequest{ @@ -103,7 +103,7 @@ d1ff7267-2fbb-4a63-a7c1-44f1a83381a7 me 2`), { Name: "list", CmdArgs: []string{"audit", "list", "--tenant", "notExisting"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.AuditServiceListRequest{ diff --git a/tests/e2e/api/image_test.go b/tests/e2e/api/image_test.go index 3941a3b..60bacb1 100644 --- a/tests/e2e/api/image_test.go +++ b/tests/e2e/api/image_test.go @@ -112,7 +112,7 @@ func Test_ImageCmd_Latest(t *testing.T) { { Name: "latest", CmdArgs: []string{"image", "latest", "--os", testresources.Image1().Id}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ImageServiceLatestRequest{ diff --git a/tests/e2e/api/project_test.go b/tests/e2e/api/project_test.go index 42fac6e..8c7c913 100644 --- a/tests/e2e/api/project_test.go +++ b/tests/e2e/api/project_test.go @@ -318,8 +318,8 @@ func Test_ProjectCmd_Apply(t *testing.T) { { Name: "apply", CmdArgs: append([]string{"project", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) }, @@ -348,8 +348,8 @@ func Test_ProjectCmd_Apply(t *testing.T) { { Name: "apply already exists", CmdArgs: append([]string{"project", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Project1()), 0755)) }, @@ -393,7 +393,7 @@ func Test_ProjectCmd_ListInvites(t *testing.T) { { Name: "list invites", CmdArgs: []string{"project", "invite", "list", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceInvitesListRequest{}, @@ -441,7 +441,7 @@ func Test_ProjectCmd_DeleteInvite(t *testing.T) { { Name: "delete", CmdArgs: []string{"project", "invite", "delete", testresources.Project1Invite().Secret, "--project", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceInviteDeleteRequest{ @@ -467,7 +467,7 @@ func Test_ProjectCmd_CreateInvite(t *testing.T) { { Name: "create invite", CmdArgs: []string{"project", "invite", "generate-join-secret", "--role", testresources.Project1Invite().Role.String(), "--project", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceInviteRequest{ @@ -499,7 +499,7 @@ func Test_ProjectCmd_Join(t *testing.T) { { Name: "join", CmdArgs: []string{"project", "invite", "join", testresources.Project1Invite().Secret}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceInviteGetRequest{ @@ -540,7 +540,7 @@ func Test_ProjectCmd_ListMembers(t *testing.T) { { Name: "list project members", CmdArgs: []string{"project", "member", "list", "--project", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceGetRequest{ @@ -590,7 +590,7 @@ func Test_ProjectCmd_DeleteMember(t *testing.T) { { Name: "delete project member", CmdArgs: []string{"project", "member", "delete", testresources.Project1Members().Id, "--project", testresources.Project1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceRemoveMemberRequest{ @@ -616,7 +616,7 @@ func Test_ProjectCmd_UpdateMember(t *testing.T) { { Name: "update project member", CmdArgs: []string{"project", "member", "update", testresources.Project1Members().Id, "--project", testresources.Project1().Uuid, "--role", testresources.Project1Members().Role.String()}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.ProjectServiceUpdateMemberRequest{ diff --git a/tests/e2e/api/tenant_test.go b/tests/e2e/api/tenant_test.go index ea5d4fc..e0693d2 100644 --- a/tests/e2e/api/tenant_test.go +++ b/tests/e2e/api/tenant_test.go @@ -113,7 +113,7 @@ func Test_TenantCmd_Create(t *testing.T) { { Name: "create", CmdArgs: []string{"tenant", "create", "--name", testresources.Tenant1().Name, "--description", testresources.Tenant1().Description, "--email", testresources.Tenant1().Email}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceCreateRequest{ @@ -135,7 +135,7 @@ func Test_TenantCmd_Create(t *testing.T) { { Name: "create from file", CmdArgs: append([]string{"tenant", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) }, @@ -163,7 +163,7 @@ func Test_TenantCmd_Create(t *testing.T) { { Name: "create many from file", CmdArgs: append([]string{"tenant", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshalToMultiYAML(t, testresources.Tenant1(), testresources.Tenant2()), 0755)) }, @@ -213,7 +213,7 @@ func Test_TenantCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"tenant", "delete", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceDeleteRequest{ @@ -232,7 +232,7 @@ func Test_TenantCmd_Delete(t *testing.T) { { Name: "delete from file", CmdArgs: append([]string{"tenant", "delete"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) }, @@ -265,7 +265,7 @@ func Test_TenantCmd_Update(t *testing.T) { { Name: "update", CmdArgs: []string{"tenant", "update", testresources.Tenant1().Login, "--name", "new-name", "--description", "new-desc"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceUpdateRequest{ @@ -286,7 +286,7 @@ func Test_TenantCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"tenant", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) }, @@ -322,8 +322,8 @@ func Test_TenantCmd_Apply(t *testing.T) { { Name: "apply", CmdArgs: append([]string{"tenant", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) }, @@ -352,8 +352,8 @@ func Test_TenantCmd_Apply(t *testing.T) { { Name: "apply already exists", CmdArgs: append([]string{"tenant", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Tenant1()), 0755)) }, @@ -399,7 +399,7 @@ func Test_TenantCmd_ListMembers(t *testing.T) { { Name: "list tenant members", CmdArgs: []string{"tenant", "member", "list", "--tenant", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceGetRequest{ @@ -449,7 +449,7 @@ func Test_TenantCmd_DeleteMember(t *testing.T) { { Name: "delete tenant member", CmdArgs: []string{"tenant", "member", "remove", testresources.Tenant1Members().Id, "--tenant", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceRemoveMemberRequest{ @@ -475,7 +475,7 @@ func Test_TenantCmd_UpdateMember(t *testing.T) { { Name: "update tenant member", CmdArgs: []string{"tenant", "member", "update", testresources.Tenant1Members().Id, "--tenant", testresources.Tenant1().Login, "--role", testresources.Tenant1Members().Role.String()}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceUpdateMemberRequest{ @@ -508,7 +508,7 @@ func Test_TenantCmd_ListInvites(t *testing.T) { { Name: "list invites", CmdArgs: []string{"tenant", "invite", "list", "--tenant", testresources.Tenant2().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceInvitesListRequest{ @@ -558,7 +558,7 @@ func Test_TenantCmd_DeleteInvite(t *testing.T) { { Name: "delete invite", CmdArgs: []string{"tenant", "invite", "delete", testresources.Tenant1Invite().Secret, "--tenant", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceInviteDeleteRequest{ @@ -584,7 +584,7 @@ func Test_TenantCmd_CreateInvite(t *testing.T) { { Name: "create invite", CmdArgs: []string{"tenant", "invite", "generate-join-secret", "--role", testresources.Tenant1Invite().Role.String(), "--tenant", testresources.Tenant1().Login}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceInviteRequest{ @@ -616,7 +616,7 @@ func Test_TenantCmd_Join(t *testing.T) { { Name: "join", CmdArgs: []string{"tenant", "invite", "join", testresources.Tenant1Invite().Secret}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TenantServiceInviteGetRequest{ diff --git a/tests/e2e/api/token_test.go b/tests/e2e/api/token_test.go index 19a9509..11b5fa1 100644 --- a/tests/e2e/api/token_test.go +++ b/tests/e2e/api/token_test.go @@ -113,7 +113,7 @@ func Test_TokenCmd_Delete(t *testing.T) { { Name: "delete", CmdArgs: []string{"token", "delete", testresources.Token1().Uuid}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TokenServiceRevokeRequest{ @@ -130,8 +130,8 @@ func Test_TokenCmd_Delete(t *testing.T) { { Name: "delete from file", CmdArgs: append([]string{"token", "delete"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) }, @@ -163,7 +163,7 @@ func Test_TokenCmd_Create(t *testing.T) { { Name: "create", CmdArgs: []string{"token", "create", "--description", testresources.Token1().Description, "--expires", durationpb.New(testresources.Token1().Expires.AsTime().Sub(e2e.TimeBubbleStartTime())).AsDuration().String()}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.TokenServiceCreateRequest{ @@ -192,8 +192,8 @@ func Test_TokenCmd_Create(t *testing.T) { { Name: "create from file", CmdArgs: append([]string{"token", "create"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) }, @@ -232,8 +232,8 @@ func Test_UpdateCmd_Update(t *testing.T) { { Name: "update from file", CmdArgs: append([]string{"token", "update"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token2()), 0755)) }, @@ -273,8 +273,8 @@ func Test_TokenCmd_Apply(t *testing.T) { { Name: "apply", CmdArgs: append([]string{"token", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) }, @@ -307,8 +307,8 @@ func Test_TokenCmd_Apply(t *testing.T) { { Name: "apply already exists", CmdArgs: append([]string{"token", "apply"}, e2e.AppendFromFileCommonArgs()...), - NewRootCmd: e2e.NewRootCmd(t, - &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, + &e2erootcmd.TestConfig{ FsMocks: func(fs *afero.Afero) { require.NoError(t, fs.WriteFile(e2e.InputFilePath, e2e.MustMarshal(t, testresources.Token1()), 0755)) }, diff --git a/tests/e2e/api/user_test.go b/tests/e2e/api/user_test.go index 50a4792..f7df29e 100644 --- a/tests/e2e/api/user_test.go +++ b/tests/e2e/api/user_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_UserCmd_Describe(t *testing.T) { @@ -15,7 +16,7 @@ func Test_UserCmd_Describe(t *testing.T) { { Name: "describe", CmdArgs: []string{"user", "describe"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.UserServiceGetRequest{}, diff --git a/tests/e2e/api/version_test.go b/tests/e2e/api/version_test.go index 0915934..724409f 100644 --- a/tests/e2e/api/version_test.go +++ b/tests/e2e/api/version_test.go @@ -6,8 +6,9 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + e2erootcmd "github.com/metal-stack/cli/testing/e2e" "github.com/metal-stack/cli/tests/e2e/testresources" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" ) func Test_VersionCmd(t *testing.T) { @@ -15,7 +16,7 @@ func Test_VersionCmd(t *testing.T) { { Name: "describe", CmdArgs: []string{"version"}, - NewRootCmd: e2e.NewRootCmd(t, &e2e.TestConfig{ + NewRootCmd: e2erootcmd.NewRootCmd(t, &e2erootcmd.TestConfig{ ClientCalls: []client.ClientCall{ { WantRequest: &apiv2.VersionServiceGetRequest{}, diff --git a/tests/e2e/testresources/audit.go b/tests/e2e/testresources/audit.go index dd6968b..de7de5c 100644 --- a/tests/e2e/testresources/audit.go +++ b/tests/e2e/testresources/audit.go @@ -2,7 +2,7 @@ package testresources import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/component.go b/tests/e2e/testresources/component.go index 34988b4..2692988 100644 --- a/tests/e2e/testresources/component.go +++ b/tests/e2e/testresources/component.go @@ -4,7 +4,7 @@ import ( "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/switch.go b/tests/e2e/testresources/switch.go index 408124c..7564b02 100644 --- a/tests/e2e/testresources/switch.go +++ b/tests/e2e/testresources/switch.go @@ -4,7 +4,7 @@ import ( "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/tasks.go b/tests/e2e/testresources/tasks.go index 1c6cbc2..b4332a5 100644 --- a/tests/e2e/testresources/tasks.go +++ b/tests/e2e/testresources/tasks.go @@ -4,7 +4,7 @@ import ( "time" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" - "github.com/metal-stack/cli/testing/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/tenants.go b/tests/e2e/testresources/tenants.go index 1665bac..c8eb5b4 100644 --- a/tests/e2e/testresources/tenants.go +++ b/tests/e2e/testresources/tenants.go @@ -4,7 +4,7 @@ import ( "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/tests/e2e/testresources/tokens.go b/tests/e2e/testresources/tokens.go index 35f8dae..467ec0b 100644 --- a/tests/e2e/testresources/tokens.go +++ b/tests/e2e/testresources/tokens.go @@ -4,7 +4,7 @@ import ( "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - e2e "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" + "github.com/metal-stack/metal-lib/pkg/genericcli/e2e" "google.golang.org/protobuf/types/known/timestamppb" )