From 647a984ff32459ca42c86783be2784c54d034a66 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Mon, 30 Sep 2024 14:21:35 +0200 Subject: [PATCH] Size reservations CRUD (#263) --- cmd/completion/size.go | 12 + cmd/size.go | 70 +---- cmd/size_reservations.go | 235 +++++++++++++++++ cmd/size_reservations_test.go | 240 ++++++++++++++++++ cmd/size_test.go | 131 ++-------- cmd/sorters/size.go | 41 ++- cmd/tableprinters/printer.go | 6 + cmd/tableprinters/size.go | 64 +++-- docs/metalctl_machine_update.md | 6 +- docs/metalctl_network_update.md | 6 +- docs/metalctl_size.md | 2 +- docs/metalctl_size_reservation.md | 54 ++++ docs/metalctl_size_reservation_apply.md | 61 +++++ docs/metalctl_size_reservation_create.md | 68 +++++ docs/metalctl_size_reservation_delete.md | 61 +++++ ... => metalctl_size_reservation_describe.md} | 11 +- docs/metalctl_size_reservation_edit.md | 46 ++++ docs/metalctl_size_reservation_list.md | 51 ++++ docs/metalctl_size_reservation_update.md | 65 +++++ ....md => metalctl_size_reservation_usage.md} | 13 +- go.mod | 55 ++-- go.sum | 148 ++++++----- 22 files changed, 1140 insertions(+), 306 deletions(-) create mode 100644 cmd/size_reservations.go create mode 100644 cmd/size_reservations_test.go create mode 100644 docs/metalctl_size_reservation.md create mode 100644 docs/metalctl_size_reservation_apply.md create mode 100644 docs/metalctl_size_reservation_create.md create mode 100644 docs/metalctl_size_reservation_delete.md rename docs/{metalctl_size_reservations.md => metalctl_size_reservation_describe.md} (86%) create mode 100644 docs/metalctl_size_reservation_edit.md create mode 100644 docs/metalctl_size_reservation_list.md create mode 100644 docs/metalctl_size_reservation_update.md rename docs/{metalctl_size_reservations_list.md => metalctl_size_reservation_usage.md} (85%) diff --git a/cmd/completion/size.go b/cmd/completion/size.go index 2ef7b777..41b878b1 100644 --- a/cmd/completion/size.go +++ b/cmd/completion/size.go @@ -16,3 +16,15 @@ func (c *Completion) SizeListCompletion(cmd *cobra.Command, args []string, toCom } return names, cobra.ShellCompDirectiveNoFileComp } + +func (c *Completion) SizeReservationsListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + resp, err := c.client.Size().ListSizeReservations(size.NewListSizeReservationsParams(), nil) + if err != nil { + return nil, cobra.ShellCompDirectiveError + } + var names []string + for _, s := range resp.Payload { + names = append(names, *s.ID) + } + return names, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/size.go b/cmd/size.go index 748bb1fa..84eca979 100644 --- a/cmd/size.go +++ b/cmd/size.go @@ -62,36 +62,7 @@ func newSizeCmd(c *config) *cobra.Command { }, } - reservationsCmd := &cobra.Command{ - Use: "reservations", - Short: "manage size reservations", - RunE: func(cmd *cobra.Command, args []string) error { - return w.listReverations() - }, - } - - listReservationsCmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "list size reservations", - RunE: func(cmd *cobra.Command, args []string) error { - return w.listReverations() - }, - } - - listReservationsCmd.Flags().String("size-id", "", "the size-id to filter") - listReservationsCmd.Flags().String("project", "", "the project to filter") - listReservationsCmd.Flags().String("tenant", "", "the tenant to filter") - listReservationsCmd.Flags().String("partition", "", "the partition to filter") - - genericcli.Must(listReservationsCmd.RegisterFlagCompletionFunc("size-id", c.comp.SizeListCompletion)) - genericcli.Must(listReservationsCmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion)) - genericcli.Must(listReservationsCmd.RegisterFlagCompletionFunc("tenant", c.comp.TenantListCompletion)) - genericcli.Must(listReservationsCmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion)) - - genericcli.AddSortFlag(listReservationsCmd, sorters.SizeReservationsSorter()) - - reservationsCmd.AddCommand(listReservationsCmd) + reservationsCmd := newSizeReservationsCmd(c) suggestCmd := &cobra.Command{ Use: "suggest ", @@ -178,11 +149,10 @@ func sizeResponseToCreate(r *models.V1SizeResponse) *models.V1SizeCreateRequest }) } return &models.V1SizeCreateRequest{ - Constraints: constraints, - Description: r.Description, - ID: r.ID, - Name: r.Name, - Reservations: r.Reservations, + Constraints: constraints, + Description: r.Description, + ID: r.ID, + Name: r.Name, } } @@ -197,36 +167,16 @@ func sizeResponseToUpdate(r *models.V1SizeResponse) *models.V1SizeUpdateRequest }) } return &models.V1SizeUpdateRequest{ - Constraints: constraints, - Description: r.Description, - ID: r.ID, - Name: r.Name, - Labels: r.Labels, - Reservations: r.Reservations, + Constraints: constraints, + Description: r.Description, + ID: r.ID, + Name: r.Name, + Labels: r.Labels, } } // non-generic command handling -func (c sizeCmd) listReverations() error { - resp, err := c.client.Size().ListSizeReservations(size.NewListSizeReservationsParams().WithBody(&models.V1SizeReservationListRequest{ - Projectid: viper.GetString("project"), - Sizeid: viper.GetString("size-id"), - Tenant: viper.GetString("tenant"), - Partitionid: viper.GetString("partition"), - }), nil) - if err != nil { - return err - } - - err = sorters.SizeReservationsSorter().SortBy(resp.Payload) - if err != nil { - return err - } - - return c.listPrinter.Print(resp.Payload) -} - func (c *sizeCmd) suggest(args []string) error { sizeid, _ := genericcli.GetExactlyOneArg(args) diff --git a/cmd/size_reservations.go b/cmd/size_reservations.go new file mode 100644 index 00000000..9ae421d3 --- /dev/null +++ b/cmd/size_reservations.go @@ -0,0 +1,235 @@ +package cmd + +import ( + "errors" + "fmt" + + sizemodel "github.com/metal-stack/metal-go/api/client/size" + "github.com/metal-stack/metal-go/api/models" + "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/metal-stack/metalctl/cmd/sorters" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type sizeReservationsCmd struct { + *config +} + +func newSizeReservationsCmd(c *config) *cobra.Command { + w := sizeReservationsCmd{ + config: c, + } + + cmdsConfig := &genericcli.CmdsConfig[*models.V1SizeReservationCreateRequest, *models.V1SizeReservationUpdateRequest, *models.V1SizeReservationResponse]{ + BinaryName: binaryName, + GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.fs), + Singular: "reservation", + Plural: "reservations", + Description: "manage size reservations", + Aliases: []string{"rs"}, + Sorter: sorters.SizeReservationsSorter(), + ValidArgsFn: c.comp.SizeReservationsListCompletion, + DescribePrinter: func() printers.Printer { return c.describePrinter }, + ListPrinter: func() printers.Printer { return c.listPrinter }, + CreateRequestFromCLI: func() (*models.V1SizeReservationCreateRequest, error) { + labels, err := genericcli.LabelsToMap(viper.GetStringSlice("labels")) + if err != nil { + return nil, err + } + + return &models.V1SizeReservationCreateRequest{ + Amount: pointer.PointerOrNil(int32(viper.GetInt32("amount"))), + Description: viper.GetString("description"), + ID: pointer.PointerOrNil(viper.GetString("id")), + Labels: labels, + Partitionids: viper.GetStringSlice("partitions"), + Projectid: pointer.PointerOrNil(viper.GetString("project")), + Sizeid: pointer.PointerOrNil(viper.GetString("size")), + }, nil + }, + CreateCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().Int32("amount", 0, "the amount to associate with this reservation") + cmd.Flags().String("id", "", "the id to associate with this reservation") + cmd.Flags().String("size", "", "the size id to associate with this reservation") + cmd.Flags().String("project", "", "the project id to associate with this reservation") + cmd.Flags().StringSlice("partitions", nil, "the partition ids to associate with this reservation") + cmd.Flags().StringSlice("labels", nil, "the labels to associate with this reservation") + cmd.Flags().String("description", "", "the description to associate with this reservation") + + genericcli.Must(cmd.RegisterFlagCompletionFunc("size", c.comp.SizeListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("partitions", c.comp.PartitionListCompletion)) + }, + UpdateRequestFromCLI: func(args []string) (*models.V1SizeReservationUpdateRequest, error) { + id, err := genericcli.GetExactlyOneArg(args) + if err != nil { + return nil, err + } + + labels, err := genericcli.LabelsToMap(viper.GetStringSlice("labels")) + if err != nil { + return nil, err + } + + return &models.V1SizeReservationUpdateRequest{ //nolint:exhaustruct + Amount: pointer.PointerOrNil(int32(viper.GetInt32("amount"))), + Description: viper.GetString("description"), + ID: &id, + Labels: labels, + Partitionids: viper.GetStringSlice("partitions"), + }, nil + }, + UpdateCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().Int32("amount", 0, "the amount to associate with this reservation") + cmd.Flags().StringSlice("partitions", nil, "the partition ids to associate with this reservation") + cmd.Flags().StringSlice("labels", nil, "the labels to associate with this reservation") + cmd.Flags().String("description", "", "the description to associate with this reservation") + + genericcli.Must(cmd.RegisterFlagCompletionFunc("partitions", c.comp.PartitionListCompletion)) + }, + ListCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("id", "", "the id to filter") + cmd.Flags().String("size", "", "the size id to filter") + cmd.Flags().String("project", "", "the project id to filter") + cmd.Flags().String("partition", "", "the partition id to filter") + + genericcli.Must(cmd.RegisterFlagCompletionFunc("id", c.comp.SizeReservationsListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("size", c.comp.SizeListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion)) + }, + } + + usageCmd := &cobra.Command{ + Use: "usage", + Short: "see current usage of size reservations", + RunE: func(cmd *cobra.Command, args []string) error { + return w.usage() + }, + } + + usageCmd.Flags().String("size-id", "", "the size-id to filter") + usageCmd.Flags().String("project", "", "the project to filter") + usageCmd.Flags().String("partition", "", "the partition to filter") + + genericcli.Must(usageCmd.RegisterFlagCompletionFunc("size-id", c.comp.SizeListCompletion)) + genericcli.Must(usageCmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion)) + genericcli.Must(usageCmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion)) + + genericcli.AddSortFlag(usageCmd, sorters.SizeReservationsUsageSorter()) + + return genericcli.NewCmds(cmdsConfig, usageCmd) +} + +func (c sizeReservationsCmd) Get(id string) (*models.V1SizeReservationResponse, error) { + resp, err := c.client.Size().GetSizeReservation(sizemodel.NewGetSizeReservationParams().WithID(id), nil) + if err != nil { + return nil, err + } + + return resp.Payload, nil +} + +func (c sizeReservationsCmd) List() ([]*models.V1SizeReservationResponse, error) { + resp, err := c.client.Size().FindSizeReservations(sizemodel.NewFindSizeReservationsParams().WithBody(&models.V1SizeReservationListRequest{ + ID: viper.GetString("id"), + Partitionid: viper.GetString("parition"), + Projectid: viper.GetString("project"), + Sizeid: viper.GetString("size"), + }), nil) + if err != nil { + return nil, err + } + + return resp.Payload, nil +} + +func (c sizeReservationsCmd) Delete(id string) (*models.V1SizeReservationResponse, error) { + resp, err := c.client.Size().DeleteSizeReservation(sizemodel.NewDeleteSizeReservationParams().WithID(id), nil) + if err != nil { + return nil, err + } + + return resp.Payload, nil +} + +func (c sizeReservationsCmd) Create(rq *models.V1SizeReservationCreateRequest) (*models.V1SizeReservationResponse, error) { + resp, err := c.client.Size().CreateSizeReservation(sizemodel.NewCreateSizeReservationParams().WithBody(rq), nil) + if err != nil { + var r *sizemodel.CreateSizeReservationConflict + if errors.As(err, &r) { + return nil, genericcli.AlreadyExistsError() + } + return nil, err + } + + return resp.Payload, nil +} + +func (c sizeReservationsCmd) Update(rq *models.V1SizeReservationUpdateRequest) (*models.V1SizeReservationResponse, error) { + resp, err := c.client.Size().UpdateSizeReservation(sizemodel.NewUpdateSizeReservationParams().WithBody(rq), nil) + if err != nil { + return nil, err + } + + return resp.Payload, nil +} + +func (c sizeReservationsCmd) Convert(r *models.V1SizeReservationResponse) (string, *models.V1SizeReservationCreateRequest, *models.V1SizeReservationUpdateRequest, error) { + if r.ID == nil { + return "", nil, nil, fmt.Errorf("id is nil") + } + return *r.ID, sizeReservationResponseToCreate(r), sizeReservationResponseToUpdate(r), nil +} + +func sizeReservationResponseToCreate(r *models.V1SizeReservationResponse) *models.V1SizeReservationCreateRequest { + return &models.V1SizeReservationCreateRequest{ + Amount: r.Amount, + Description: r.Description, + ID: r.ID, + Labels: r.Labels, + Name: r.Name, + Partitionids: r.Partitionids, + Projectid: r.Projectid, + Sizeid: r.Sizeid, + } +} + +func sizeReservationResponseToUpdate(r *models.V1SizeReservationResponse) *models.V1SizeReservationUpdateRequest { + return &models.V1SizeReservationUpdateRequest{ + Amount: r.Amount, + Description: r.Description, + ID: r.ID, + Labels: r.Labels, + Name: r.Name, + Partitionids: r.Partitionids, + } +} + +// non-generic command handling + +func (c *sizeReservationsCmd) usage() error { + sortKeys, err := genericcli.ParseSortFlags() + if err != nil { + return err + } + + resp, err := c.client.Size().SizeReservationsUsage(sizemodel.NewSizeReservationsUsageParams().WithBody(&models.V1SizeReservationListRequest{ + Partitionid: viper.GetString("parition"), + Projectid: viper.GetString("project"), + Sizeid: viper.GetString("size"), + }), nil) + if err != nil { + return err + } + + err = sorters.SizeReservationsUsageSorter().SortBy(resp.Payload, sortKeys...) + if err != nil { + return err + } + + return c.listPrinter.Print(resp.Payload) +} diff --git a/cmd/size_reservations_test.go b/cmd/size_reservations_test.go new file mode 100644 index 00000000..40baf88c --- /dev/null +++ b/cmd/size_reservations_test.go @@ -0,0 +1,240 @@ +package cmd + +import ( + "testing" + + "github.com/metal-stack/metal-go/api/client/size" + "github.com/metal-stack/metal-go/api/models" + "github.com/metal-stack/metal-go/test/client" + "github.com/metal-stack/metal-lib/pkg/pointer" + "github.com/metal-stack/metal-lib/pkg/testcommon" + "github.com/spf13/afero" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +var ( + rv1 = &models.V1SizeReservationResponse{ + Amount: pointer.Pointer(int32(3)), + Description: "this is reservation 1", + ID: pointer.Pointer("r1"), + Labels: map[string]string{ + "a": "b", + }, + Name: "reservation 1", + Partitionids: []string{"partition-a", "partition-b"}, + Projectid: pointer.Pointer("project-a"), + Sizeid: pointer.Pointer("size-a"), + } + rv2 = &models.V1SizeReservationResponse{ + Amount: pointer.Pointer(int32(2)), + Description: "this is reservation 2", + ID: pointer.Pointer("r2"), + Labels: map[string]string{ + "b": "c", + }, + Name: "reservation 2", + Partitionids: []string{"partition-b"}, + Projectid: pointer.Pointer("project-b"), + Sizeid: pointer.Pointer("size-b"), + } +) + +func Test_SizeReservationCmd_MultiResult(t *testing.T) { + tests := []*test[[]*models.V1SizeReservationResponse]{ + { + name: "list", + cmd: func(want []*models.V1SizeReservationResponse) []string { + return []string{"size", "reservation", "list"} + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("FindSizeReservations", testcommon.MatchIgnoreContext(t, size.NewFindSizeReservationsParams().WithBody(&models.V1SizeReservationListRequest{})), nil).Return(&size.FindSizeReservationsOK{ + Payload: []*models.V1SizeReservationResponse{ + rv2, + rv1, + }, + }, nil) + }, + }, + want: []*models.V1SizeReservationResponse{ + rv1, + rv2, + }, + wantTable: pointer.Pointer(` +ID SIZE PROJECT PARTITIONS DESCRIPTION AMOUNT +r1 size-a project-a partition-a, partition-b this is reservation 1 3 +r2 size-b project-b partition-b this is reservation 2 2 +`), + wantWideTable: pointer.Pointer(` +ID SIZE PROJECT PARTITIONS DESCRIPTION AMOUNT LABELS +r1 size-a project-a partition-a, partition-b this is reservation 1 3 a=b +r2 size-b project-b partition-b this is reservation 2 2 b=c +`), + template: pointer.Pointer("{{ .id }} {{ .name }}"), + wantTemplate: pointer.Pointer(` +r1 reservation 1 +r2 reservation 2 +`), + wantMarkdown: pointer.Pointer(` +| ID | SIZE | PROJECT | PARTITIONS | DESCRIPTION | AMOUNT | +|----|--------|-----------|--------------------------|-----------------------|--------| +| r1 | size-a | project-a | partition-a, partition-b | this is reservation 1 | 3 | +| r2 | size-b | project-b | partition-b | this is reservation 2 | 2 | +`), + }, + { + name: "apply", + cmd: func(want []*models.V1SizeReservationResponse) []string { + return appendFromFileCommonArgs("size", "reservation", "apply") + }, + fsMocks: func(fs afero.Fs, want []*models.V1SizeReservationResponse) { + require.NoError(t, afero.WriteFile(fs, "/file.yaml", mustMarshalToMultiYAML(t, want), 0755)) + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("CreateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewCreateSizeReservationParams().WithBody(sizeReservationResponseToCreate(rv1))), nil).Return(nil, &size.CreateSizeReservationConflict{}).Once() + mock.On("UpdateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewUpdateSizeReservationParams().WithBody(sizeReservationResponseToUpdate(rv1))), nil).Return(&size.UpdateSizeReservationOK{ + Payload: rv1, + }, nil) + mock.On("CreateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewCreateSizeReservationParams().WithBody(sizeReservationResponseToCreate(rv2))), nil).Return(&size.CreateSizeReservationCreated{ + Payload: rv2, + }, nil) + }, + }, + want: []*models.V1SizeReservationResponse{ + rv1, + rv2, + }, + }, + { + name: "create from file", + cmd: func(want []*models.V1SizeReservationResponse) []string { + return appendFromFileCommonArgs("size", "reservation", "create") + }, + fsMocks: func(fs afero.Fs, want []*models.V1SizeReservationResponse) { + require.NoError(t, afero.WriteFile(fs, "/file.yaml", mustMarshalToMultiYAML(t, want), 0755)) + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("CreateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewCreateSizeReservationParams().WithBody(sizeReservationResponseToCreate(rv1))), nil).Return(&size.CreateSizeReservationCreated{ + Payload: rv1, + }, nil) + }, + }, + want: []*models.V1SizeReservationResponse{ + rv1, + }, + }, + { + name: "update from file", + cmd: func(want []*models.V1SizeReservationResponse) []string { + return appendFromFileCommonArgs("size", "reservation", "update") + }, + fsMocks: func(fs afero.Fs, want []*models.V1SizeReservationResponse) { + require.NoError(t, afero.WriteFile(fs, "/file.yaml", mustMarshalToMultiYAML(t, want), 0755)) + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("UpdateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewUpdateSizeReservationParams().WithBody(sizeReservationResponseToUpdate(rv1))), nil).Return(&size.UpdateSizeReservationOK{ + Payload: rv1, + }, nil) + }, + }, + want: []*models.V1SizeReservationResponse{ + rv1, + }, + }, + } + for _, tt := range tests { + tt.testCmd(t) + } +} + +func Test_SizeReservationCmd_SingleResult(t *testing.T) { + tests := []*test[*models.V1SizeReservationResponse]{ + { + name: "describe", + cmd: func(want *models.V1SizeReservationResponse) []string { + return []string{"size", "reservation", "describe", *want.ID} + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("GetSizeReservation", testcommon.MatchIgnoreContext(t, size.NewGetSizeReservationParams().WithID(*rv1.ID)), nil).Return(&size.GetSizeReservationOK{ + Payload: rv1, + }, nil) + }, + }, + want: rv1, + wantTable: pointer.Pointer(` +ID SIZE PROJECT PARTITIONS DESCRIPTION AMOUNT +r1 size-a project-a partition-a, partition-b this is reservation 1 3 + `), + wantWideTable: pointer.Pointer(` +ID SIZE PROJECT PARTITIONS DESCRIPTION AMOUNT LABELS +r1 size-a project-a partition-a, partition-b this is reservation 1 3 a=b + `), + template: pointer.Pointer("{{ .id }} {{ .name }}"), + wantTemplate: pointer.Pointer(` +r1 reservation 1 + `), + wantMarkdown: pointer.Pointer(` +| ID | SIZE | PROJECT | PARTITIONS | DESCRIPTION | AMOUNT | +|----|--------|-----------|--------------------------|-----------------------|--------| +| r1 | size-a | project-a | partition-a, partition-b | this is reservation 1 | 3 | + `), + }, + { + name: "delete", + cmd: func(want *models.V1SizeReservationResponse) []string { + return []string{"size", "reservation", "rm", *want.ID} + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("DeleteSizeReservation", testcommon.MatchIgnoreContext(t, size.NewDeleteSizeReservationParams().WithID(*rv1.ID)), nil).Return(&size.DeleteSizeReservationOK{ + Payload: rv1, + }, nil) + }, + }, + want: rv1, + }, + { + name: "create from file", + cmd: func(want *models.V1SizeReservationResponse) []string { + return []string{"size", "reservation", "create", "-f", "/file.yaml"} + }, + fsMocks: func(fs afero.Fs, want *models.V1SizeReservationResponse) { + require.NoError(t, afero.WriteFile(fs, "/file.yaml", mustMarshal(t, want), 0755)) + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("CreateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewCreateSizeReservationParams().WithBody(sizeReservationResponseToCreate(rv1))), nil).Return(&size.CreateSizeReservationCreated{ + Payload: rv1, + }, nil) + }, + }, + want: rv1, + }, + { + name: "update from file", + cmd: func(want *models.V1SizeReservationResponse) []string { + return []string{"size", "reservation", "update", "-f", "/file.yaml"} + }, + fsMocks: func(fs afero.Fs, want *models.V1SizeReservationResponse) { + require.NoError(t, afero.WriteFile(fs, "/file.yaml", mustMarshal(t, want), 0755)) + }, + mocks: &client.MetalMockFns{ + Size: func(mock *mock.Mock) { + mock.On("UpdateSizeReservation", testcommon.MatchIgnoreContext(t, size.NewUpdateSizeReservationParams().WithBody(sizeReservationResponseToUpdate(rv1))), nil).Return(&size.UpdateSizeReservationOK{ + Payload: rv1, + }, nil) + }, + }, + want: rv1, + }, + } + for _, tt := range tests { + tt.testCmd(t) + } +} diff --git a/cmd/size_test.go b/cmd/size_test.go index 3bb29ec2..fc4440d5 100644 --- a/cmd/size_test.go +++ b/cmd/size_test.go @@ -41,26 +41,6 @@ var ( Identifier: "AD120GL*", }, }, - Reservations: []*models.V1SizeReservation{ - { - Amount: pointer.Pointer(int32(5)), - Description: "for testing", - Partitionids: []string{*partition1.ID}, - Projectid: pointer.Pointer(project1.Meta.ID), - Labels: map[string]string{ - "size.metal-stack.io/reserved-by": "admin", - }, - }, - { - Amount: pointer.Pointer(int32(2)), - Description: "for testing", - Partitionids: []string{*partition2.ID}, - Projectid: pointer.Pointer(project2.Meta.ID), - Labels: map[string]string{ - "size.metal-stack.io/reserved-by": "admin", - }, - }, - }, Labels: map[string]string{ "size.metal-stack.io/cpu-description": "1x Intel(R) Xeon(R) D-2141I CPU @ 2.20GHz", "size.metal-stack.io/drive-description": "960GB NVMe", @@ -115,15 +95,15 @@ func Test_SizeCmd_MultiResult(t *testing.T) { size2, }, wantTable: pointer.Pointer(` -ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE -1 size-1 size 1 7 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 -2 size-2 size 2 0 5 - 6 3 B - 4 B 1 B - 2 B +ID NAME DESCRIPTION CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE +1 size-1 size 1 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 +2 size-2 size 2 5 - 6 3 B - 4 B 1 B - 2 B `), wantWideTable: pointer.Pointer(` -ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE LABELS -1 size-1 size 1 7 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 size.metal-stack.io/cpu-description=1x Intel(R) Xeon(R) D-2141I CPU @ 2.20GHz - size.metal-stack.io/drive-description=960GB NVMe -2 size-2 size 2 0 5 - 6 3 B - 4 B 1 B - 2 B +ID NAME DESCRIPTION CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE LABELS +1 size-1 size 1 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 size.metal-stack.io/cpu-description=1x Intel(R) Xeon(R) D-2141I CPU @ 2.20GHz + size.metal-stack.io/drive-description=960GB NVMe +2 size-2 size 2 5 - 6 3 B - 4 B 1 B - 2 B `), template: pointer.Pointer("{{ .id }} {{ .name }}"), wantTemplate: pointer.Pointer(` @@ -131,10 +111,10 @@ ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RA 2 size-2 `), wantMarkdown: pointer.Pointer(` -| ID | NAME | DESCRIPTION | RESERVATIONS | CPU RANGE | MEMORY RANGE | STORAGE RANGE | GPU RANGE | -|----|--------|-------------|--------------|-----------|--------------|---------------|-----------------| -| 1 | size-1 | size 1 | 7 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | AD120GL*: 1 - 1 | -| 2 | size-2 | size 2 | 0 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | | +| ID | NAME | DESCRIPTION | CPU RANGE | MEMORY RANGE | STORAGE RANGE | GPU RANGE | +|----|--------|-------------|-----------|--------------|---------------|-----------------| +| 1 | size-1 | size 1 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | AD120GL*: 1 - 1 | +| 2 | size-2 | size 2 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | | `), }, { @@ -240,22 +220,22 @@ func Test_SizeCmd_SingleResult(t *testing.T) { }, want: size1, wantTable: pointer.Pointer(` -ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE -1 size-1 size 1 7 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 +ID NAME DESCRIPTION CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE +1 size-1 size 1 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 `), wantWideTable: pointer.Pointer(` -ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE LABELS -1 size-1 size 1 7 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 size.metal-stack.io/cpu-description=1x Intel(R) Xeon(R) D-2141I CPU @ 2.20GHz - size.metal-stack.io/drive-description=960GB NVMe +ID NAME DESCRIPTION CPU RANGE MEMORY RANGE STORAGE RANGE GPU RANGE LABELS +1 size-1 size 1 5 - 6 3 B - 4 B 1 B - 2 B AD120GL*: 1 - 1 size.metal-stack.io/cpu-description=1x Intel(R) Xeon(R) D-2141I CPU @ 2.20GHz + size.metal-stack.io/drive-description=960GB NVMe `), template: pointer.Pointer("{{ .id }} {{ .name }}"), wantTemplate: pointer.Pointer(` 1 size-1 `), wantMarkdown: pointer.Pointer(` -| ID | NAME | DESCRIPTION | RESERVATIONS | CPU RANGE | MEMORY RANGE | STORAGE RANGE | GPU RANGE | -|----|--------|-------------|--------------|-----------|--------------|---------------|-----------------| -| 1 | size-1 | size 1 | 7 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | AD120GL*: 1 - 1 | +| ID | NAME | DESCRIPTION | CPU RANGE | MEMORY RANGE | STORAGE RANGE | GPU RANGE | +|----|--------|-------------|-----------|--------------|---------------|-----------------| +| 1 | size-1 | size 1 | 5 - 6 | 3 B - 4 B | 1 B - 2 B | AD120GL*: 1 - 1 | `), }, { @@ -296,7 +276,6 @@ ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RA Type: size1.Constraints[0].Type, }, } - s.Reservations = nil mock.On("CreateSize", testcommon.MatchIgnoreContext(t, size.NewCreateSizeParams().WithBody(sizeResponseToCreate(size1))), nil).Return(&size.CreateSizeCreated{ Payload: size1, }, nil) @@ -371,75 +350,3 @@ ID NAME DESCRIPTION RESERVATIONS CPU RANGE MEMORY RANGE STORAGE RA tt.testCmd(t) } } - -func Test_SizeReservationsCmd_MultiResult(t *testing.T) { - reservations := []*models.V1SizeReservationResponse{ - { - Partitionid: pointer.Pointer("a"), - Projectallocations: pointer.Pointer(int32(10)), - Projectid: pointer.Pointer("1"), - Projectname: pointer.Pointer("project-1"), - Reservations: pointer.Pointer(int32(5)), - Sizeid: pointer.Pointer("size-1"), - Tenant: pointer.Pointer("tenant-1"), - Usedreservations: pointer.Pointer(int32(5)), - Labels: map[string]string{ - "size.metal-stack.io/reserved-by": "admin", - }, - }, - { - Partitionid: pointer.Pointer("b"), - Projectallocations: pointer.Pointer(int32(1)), - Projectid: pointer.Pointer("2"), - Projectname: pointer.Pointer("project-2"), - Reservations: pointer.Pointer(int32(3)), - Sizeid: pointer.Pointer("size-2"), - Tenant: pointer.Pointer("tenant-2"), - Usedreservations: pointer.Pointer(int32(1)), - Labels: map[string]string{ - "size.metal-stack.io/reserved-by": "admin", - }, - }, - } - - tests := []*test[[]*models.V1SizeReservationResponse]{ - { - name: "reservation list", - cmd: func(want []*models.V1SizeReservationResponse) []string { - args := []string{"size", "reservations", "list", "--partition", "partition-1", "--project", "project-1", "--size-id", "size-1", "--tenant", "tenant-1"} - assertExhaustiveArgs(t, args, "sort-by") - return args - }, - mocks: &client.MetalMockFns{ - Size: func(mock *mock.Mock) { - mock.On("ListSizeReservations", testcommon.MatchIgnoreContext(t, size.NewListSizeReservationsParams().WithBody(&models.V1SizeReservationListRequest{ - Projectid: "project-1", - Sizeid: "size-1", - Tenant: "tenant-1", - Partitionid: "partition-1", - })), nil).Return(&size.ListSizeReservationsOK{Payload: reservations}, nil) - }, - }, - want: reservations, - wantTable: pointer.Pointer(` -PARTITION SIZE TENANT PROJECT PROJECT NAME USED/AMOUNT PROJECT ALLOCATIONS -a size-1 tenant-1 1 project-1 5/5 10 -b size-2 tenant-2 2 project-2 1/3 1 -`), - wantWideTable: pointer.Pointer(` -PARTITION SIZE TENANT PROJECT PROJECT NAME USED/AMOUNT PROJECT ALLOCATIONS LABELS -a size-1 tenant-1 1 project-1 5/5 10 size.metal-stack.io/reserved-by=admin -b size-2 tenant-2 2 project-2 1/3 1 size.metal-stack.io/reserved-by=admin -`), - wantMarkdown: pointer.Pointer(` -| PARTITION | SIZE | TENANT | PROJECT | PROJECT NAME | USED/AMOUNT | PROJECT ALLOCATIONS | -|-----------|--------|----------|---------|--------------|-------------|---------------------| -| a | size-1 | tenant-1 | 1 | project-1 | 5/5 | 10 | -| b | size-2 | tenant-2 | 2 | project-2 | 1/3 | 1 | -`), - }, - } - for _, tt := range tests { - tt.testCmd(t) - } -} diff --git a/cmd/sorters/size.go b/cmd/sorters/size.go index ed6e8be9..94f799b9 100644 --- a/cmd/sorters/size.go +++ b/cmd/sorters/size.go @@ -1,6 +1,9 @@ package sorters import ( + "slices" + "strings" + "github.com/metal-stack/metal-go/api/models" "github.com/metal-stack/metal-lib/pkg/multisort" "github.com/metal-stack/metal-lib/pkg/pointer" @@ -24,16 +27,44 @@ func SizeSorter() *multisort.Sorter[*models.V1SizeResponse] { func SizeReservationsSorter() *multisort.Sorter[*models.V1SizeReservationResponse] { return multisort.New(multisort.FieldMap[*models.V1SizeReservationResponse]{ "partition": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { - return multisort.Compare(pointer.SafeDeref(a.Partitionid), pointer.SafeDeref(b.Partitionid), descending) + slices.Sort(a.Partitionids) + slices.Sort(b.Partitionids) + return multisort.Compare(strings.Join(a.Partitionids, " "), strings.Join(b.Partitionids, " "), descending) }, "size": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { return multisort.Compare(pointer.SafeDeref(a.Sizeid), pointer.SafeDeref(b.Sizeid), descending) }, - "tenant": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { - return multisort.Compare(pointer.SafeDeref(a.Tenant), pointer.SafeDeref(b.Tenant), descending) - }, "project": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { return multisort.Compare(pointer.SafeDeref(a.Projectid), pointer.SafeDeref(b.Projectid), descending) }, - }, multisort.Keys{{ID: "partition"}, {ID: "size"}, {ID: "tenant"}, {ID: "project"}}) + "amount": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Amount), pointer.SafeDeref(b.Amount), descending) + }, + "id": func(a, b *models.V1SizeReservationResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.ID), pointer.SafeDeref(b.ID), descending) + }, + }, multisort.Keys{{ID: "project"}, {ID: "size"}, {ID: "partition"}, {ID: "id"}}) +} + +func SizeReservationsUsageSorter() *multisort.Sorter[*models.V1SizeReservationUsageResponse] { + return multisort.New(multisort.FieldMap[*models.V1SizeReservationUsageResponse]{ + "partition": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Partitionid), pointer.SafeDeref(b.Partitionid), descending) + }, + "size": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Sizeid), pointer.SafeDeref(b.Sizeid), descending) + }, + "project": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Projectid), pointer.SafeDeref(b.Projectid), descending) + }, + "id": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.ID), pointer.SafeDeref(b.ID), descending) + }, + "amount": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Amount), pointer.SafeDeref(b.Amount), descending) + }, + "used-amount": func(a, b *models.V1SizeReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(pointer.SafeDeref(a.Usedamount), pointer.SafeDeref(b.Usedamount), descending) + }, + }, multisort.Keys{{ID: "project"}, {ID: "size"}, {ID: "partition"}, {ID: "id"}}) } diff --git a/cmd/tableprinters/printer.go b/cmd/tableprinters/printer.go index 401b482f..8d3ef5bc 100644 --- a/cmd/tableprinters/printer.go +++ b/cmd/tableprinters/printer.go @@ -102,6 +102,7 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin return t.FSLTable(d, wide) case *api.Contexts: return t.ContextTable(d, wide) + case *models.V1SizeImageConstraintResponse: return t.SizeImageConstraintTable(pointer.WrapInSlice(d), wide) case []*models.V1SizeImageConstraintResponse: @@ -114,6 +115,11 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin return t.SizeReservationTable(pointer.WrapInSlice(d), wide) case []*models.V1SizeReservationResponse: return t.SizeReservationTable(d, wide) + case *models.V1SizeReservationUsageResponse: + return t.SizeReservationUsageTable(pointer.WrapInSlice(d), wide) + case []*models.V1SizeReservationUsageResponse: + return t.SizeReservationUsageTable(d, wide) + default: return nil, nil, fmt.Errorf("unknown table printer for type: %T", d) } diff --git a/cmd/tableprinters/size.go b/cmd/tableprinters/size.go index d0973ac8..4a1932f3 100644 --- a/cmd/tableprinters/size.go +++ b/cmd/tableprinters/size.go @@ -15,12 +15,12 @@ import ( func (t *TablePrinter) SizeTable(data []*models.V1SizeResponse, wide bool) ([]string, [][]string, error) { var ( - header = []string{"ID", "Name", "Description", "Reservations", "CPU Range", "Memory Range", "Storage Range", "GPU Range"} + header = []string{"ID", "Name", "Description", "CPU Range", "Memory Range", "Storage Range", "GPU Range"} rows [][]string ) if wide { - header = []string{"ID", "Name", "Description", "Reservations", "CPU Range", "Memory Range", "Storage Range", "GPU Range", "Labels"} + header = []string{"ID", "Name", "Description", "CPU Range", "Memory Range", "Storage Range", "GPU Range", "Labels"} } for _, size := range data { @@ -39,13 +39,7 @@ func (t *TablePrinter) SizeTable(data []*models.V1SizeResponse, wide bool) ([]st } - reservationCount := 0 - for _, r := range size.Reservations { - r := r - reservationCount += int(pointer.SafeDeref(r.Amount)) - } - - row := []string{pointer.SafeDeref(size.ID), size.Name, size.Description, strconv.Itoa(reservationCount), cpu, memory, storage, gpu} + row := []string{pointer.SafeDeref(size.ID), size.Name, size.Description, cpu, memory, storage, gpu} if wide { labels := genericcli.MapToLabels(size.Labels) @@ -65,7 +59,7 @@ func (t *TablePrinter) SizeTable(data []*models.V1SizeResponse, wide bool) ([]st func (t *TablePrinter) SizeReservationTable(data []*models.V1SizeReservationResponse, wide bool) ([]string, [][]string, error) { var ( - header = []string{"Partition", "Size", "Tenant", "Project", "Project Name", "Used/Amount", "Project Allocations"} + header = []string{"ID", "Size", "Project", "Partitions", "Description", "Amount"} rows [][]string ) @@ -76,14 +70,18 @@ func (t *TablePrinter) SizeReservationTable(data []*models.V1SizeReservationResp for _, d := range data { d := d + desc := d.Description + if !wide { + desc = genericcli.TruncateEnd(d.Description, 50) + } + row := []string{ - pointer.SafeDeref(d.Partitionid), + pointer.SafeDeref(d.ID), pointer.SafeDeref(d.Sizeid), - pointer.SafeDeref(d.Tenant), pointer.SafeDeref(d.Projectid), - pointer.SafeDeref(d.Projectname), - fmt.Sprintf("%d/%d", pointer.SafeDeref(d.Usedreservations), pointer.SafeDeref(d.Reservations)), - strconv.Itoa(int(pointer.SafeDeref(d.Projectallocations))), + strings.Join(d.Partitionids, ", "), + desc, + fmt.Sprintf("%d", pointer.SafeDeref(d.Amount)), } if wide { @@ -97,3 +95,39 @@ func (t *TablePrinter) SizeReservationTable(data []*models.V1SizeReservationResp return header, rows, nil } + +func (t *TablePrinter) SizeReservationUsageTable(data []*models.V1SizeReservationUsageResponse, wide bool) ([]string, [][]string, error) { + var ( + header = []string{"ID", "Size", "Project", "Partition", "Used/Amount"} + rows [][]string + ) + + if wide { + header = append(header, "Allocated", "Labels") + } + + for _, d := range data { + d := d + + row := []string{ + pointer.SafeDeref(d.ID), + pointer.SafeDeref(d.Sizeid), + pointer.SafeDeref(d.Projectid), + pointer.SafeDeref(d.Partitionid), + fmt.Sprintf("%d/%d", pointer.SafeDeref(d.Usedamount), pointer.SafeDeref(d.Amount)), + } + + if wide { + labels := genericcli.MapToLabels(d.Labels) + sort.Strings(labels) + row = append(row, + strconv.Itoa(int(pointer.SafeDeref(d.Projectallocations))), + strings.Join(labels, "\n"), + ) + } + + rows = append(rows, row) + } + + return header, rows, nil +} diff --git a/docs/metalctl_machine_update.md b/docs/metalctl_machine_update.md index fac0b157..752352c0 100644 --- a/docs/metalctl_machine_update.md +++ b/docs/metalctl_machine_update.md @@ -3,7 +3,7 @@ updates the machine ``` -metalctl machine update [flags] +metalctl machine update [flags] ``` ### Options @@ -18,9 +18,9 @@ metalctl machine update [flags] $ metalctl machine describe machine-1 -o yaml > machine.yaml $ vi machine.yaml $ # either via stdin - $ cat machine.yaml | metalctl machine update -f - + $ cat machine.yaml | metalctl machine update -f - $ # or via file - $ metalctl machine update -f machine.yaml + $ metalctl machine update -f machine.yaml the file can also contain multiple documents and perform a bulk operation. diff --git a/docs/metalctl_network_update.md b/docs/metalctl_network_update.md index 0e74b925..13c04e23 100644 --- a/docs/metalctl_network_update.md +++ b/docs/metalctl_network_update.md @@ -3,7 +3,7 @@ updates the network ``` -metalctl network update [flags] +metalctl network update [flags] ``` ### Options @@ -20,9 +20,9 @@ metalctl network update [flags] $ metalctl network describe network-1 -o yaml > network.yaml $ vi network.yaml $ # either via stdin - $ cat network.yaml | metalctl network update -f - + $ cat network.yaml | metalctl network update -f - $ # or via file - $ metalctl network update -f network.yaml + $ metalctl network update -f network.yaml the file can also contain multiple documents and perform a bulk operation. diff --git a/docs/metalctl_size.md b/docs/metalctl_size.md index 790c38a6..62e50669 100644 --- a/docs/metalctl_size.md +++ b/docs/metalctl_size.md @@ -50,7 +50,7 @@ a size matches a machine in terms of cpu cores, ram and storage. * [metalctl size edit](metalctl_size_edit.md) - edit the size through an editor and update * [metalctl size imageconstraint](metalctl_size_imageconstraint.md) - manage imageconstraint entities * [metalctl size list](metalctl_size_list.md) - list all sizes -* [metalctl size reservations](metalctl_size_reservations.md) - manage size reservations +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities * [metalctl size suggest](metalctl_size_suggest.md) - suggest size from a given machine id * [metalctl size update](metalctl_size_update.md) - updates the size diff --git a/docs/metalctl_size_reservation.md b/docs/metalctl_size_reservation.md new file mode 100644 index 00000000..5fe364da --- /dev/null +++ b/docs/metalctl_size_reservation.md @@ -0,0 +1,54 @@ +## metalctl size reservation + +manage reservation entities + +### Synopsis + +manage size reservations + +### Options + +``` + -h, --help help for reservation +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size](metalctl_size.md) - manage size entities +* [metalctl size reservation apply](metalctl_size_reservation_apply.md) - applies one or more reservations from a given file +* [metalctl size reservation create](metalctl_size_reservation_create.md) - creates the reservation +* [metalctl size reservation delete](metalctl_size_reservation_delete.md) - deletes the reservation +* [metalctl size reservation describe](metalctl_size_reservation_describe.md) - describes the reservation +* [metalctl size reservation edit](metalctl_size_reservation_edit.md) - edit the reservation through an editor and update +* [metalctl size reservation list](metalctl_size_reservation_list.md) - list all reservations +* [metalctl size reservation update](metalctl_size_reservation_update.md) - updates the reservation +* [metalctl size reservation usage](metalctl_size_reservation_usage.md) - see current usage of size reservations + diff --git a/docs/metalctl_size_reservation_apply.md b/docs/metalctl_size_reservation_apply.md new file mode 100644 index 00000000..77b290b0 --- /dev/null +++ b/docs/metalctl_size_reservation_apply.md @@ -0,0 +1,61 @@ +## metalctl size reservation apply + +applies one or more reservations from a given file + +``` +metalctl size reservation apply [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. + -f, --file string filename of the create or update request in yaml format, or - for stdin. + + Example: + $ metalctl reservation describe reservation-1 -o yaml > reservation.yaml + $ vi reservation.yaml + $ # either via stdin + $ cat reservation.yaml | metalctl reservation apply -f - + $ # or via file + $ metalctl reservation apply -f reservation.yaml + + the file can also contain multiple documents and perform a bulk operation. + + -h, --help help for apply + --skip-security-prompts skips security prompt for bulk operations + --timestamps when used with --file (bulk operation): prints timestamps in-between the operations +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservation_create.md b/docs/metalctl_size_reservation_create.md new file mode 100644 index 00000000..51b9c53a --- /dev/null +++ b/docs/metalctl_size_reservation_create.md @@ -0,0 +1,68 @@ +## metalctl size reservation create + +creates the reservation + +``` +metalctl size reservation create [flags] +``` + +### Options + +``` + --amount int32 the amount to associate with this reservation + --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 the description to associate with this reservation + -f, --file string filename of the create or update request in yaml format, or - for stdin. + + Example: + $ metalctl reservation describe reservation-1 -o yaml > reservation.yaml + $ vi reservation.yaml + $ # either via stdin + $ cat reservation.yaml | metalctl reservation create -f - + $ # or via file + $ metalctl reservation create -f reservation.yaml + + the file can also contain multiple documents and perform a bulk operation. + + -h, --help help for create + --id string the id to associate with this reservation + --labels strings the labels to associate with this reservation + --partitions strings the partition ids to associate with this reservation + --project string the project id to associate with this reservation + --size string the size id to associate with this reservation + --skip-security-prompts skips security prompt for bulk operations + --timestamps when used with --file (bulk operation): prints timestamps in-between the operations +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservation_delete.md b/docs/metalctl_size_reservation_delete.md new file mode 100644 index 00000000..70e38160 --- /dev/null +++ b/docs/metalctl_size_reservation_delete.md @@ -0,0 +1,61 @@ +## metalctl size reservation delete + +deletes the reservation + +``` +metalctl size reservation delete [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. + -f, --file string filename of the create or update request in yaml format, or - for stdin. + + Example: + $ metalctl reservation describe reservation-1 -o yaml > reservation.yaml + $ vi reservation.yaml + $ # either via stdin + $ cat reservation.yaml | metalctl reservation delete -f - + $ # or via file + $ metalctl reservation delete -f reservation.yaml + + the file can also contain multiple documents and perform a bulk operation. + + -h, --help help for delete + --skip-security-prompts skips security prompt for bulk operations + --timestamps when used with --file (bulk operation): prints timestamps in-between the operations +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservations.md b/docs/metalctl_size_reservation_describe.md similarity index 86% rename from docs/metalctl_size_reservations.md rename to docs/metalctl_size_reservation_describe.md index 7fefef08..53935529 100644 --- a/docs/metalctl_size_reservations.md +++ b/docs/metalctl_size_reservation_describe.md @@ -1,15 +1,15 @@ -## metalctl size reservations +## metalctl size reservation describe -manage size reservations +describes the reservation ``` -metalctl size reservations [flags] +metalctl size reservation describe [flags] ``` ### Options ``` - -h, --help help for reservations + -h, --help help for describe ``` ### Options inherited from parent commands @@ -42,6 +42,5 @@ metalctl size reservations [flags] ### SEE ALSO -* [metalctl size](metalctl_size.md) - manage size entities -* [metalctl size reservations list](metalctl_size_reservations_list.md) - list size reservations +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities diff --git a/docs/metalctl_size_reservation_edit.md b/docs/metalctl_size_reservation_edit.md new file mode 100644 index 00000000..d63b0b37 --- /dev/null +++ b/docs/metalctl_size_reservation_edit.md @@ -0,0 +1,46 @@ +## metalctl size reservation edit + +edit the reservation through an editor and update + +``` +metalctl size reservation edit [flags] +``` + +### Options + +``` + -h, --help help for edit +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservation_list.md b/docs/metalctl_size_reservation_list.md new file mode 100644 index 00000000..f995bc10 --- /dev/null +++ b/docs/metalctl_size_reservation_list.md @@ -0,0 +1,51 @@ +## metalctl size reservation list + +list all reservations + +``` +metalctl size reservation list [flags] +``` + +### Options + +``` + -h, --help help for list + --id string the id to filter + --partition string the partition id to filter + --project string the project id to filter + --size string the size id to filter + --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: amount|id|partition|project|size +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservation_update.md b/docs/metalctl_size_reservation_update.md new file mode 100644 index 00000000..47e19a03 --- /dev/null +++ b/docs/metalctl_size_reservation_update.md @@ -0,0 +1,65 @@ +## metalctl size reservation update + +updates the reservation + +``` +metalctl size reservation update [flags] +``` + +### Options + +``` + --amount int32 the amount to associate with this reservation + --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 the description to associate with this reservation + -f, --file string filename of the create or update request in yaml format, or - for stdin. + + Example: + $ metalctl reservation describe reservation-1 -o yaml > reservation.yaml + $ vi reservation.yaml + $ # either via stdin + $ cat reservation.yaml | metalctl reservation update -f - + $ # or via file + $ metalctl reservation update -f reservation.yaml + + the file can also contain multiple documents and perform a bulk operation. + + -h, --help help for update + --labels strings the labels to associate with this reservation + --partitions strings the partition ids to associate with this reservation + --skip-security-prompts skips security prompt for bulk operations + --timestamps when used with --file (bulk operation): prints timestamps in-between the operations +``` + +### Options inherited from parent commands + +``` + --api-token string api token to authenticate. Can be specified with METALCTL_API_TOKEN environment variable. + --api-url string api server address. Can be specified with METALCTL_API_URL environment variable. + -c, --config string alternative config file path, (default is ~/.metalctl/config.yaml). + Example config.yaml: + + --- + apitoken: "alongtoken" + ... + + + --debug debug output + --force-color force colored output even without tty + --kubeconfig string Path to the kube-config to use for authentication and authorization. Is updated by login. Uses default path if not specified. + --no-headers do not print headers of table output format (default print headers) + -o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (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. + Example for machines: + + metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}" + + + --yes-i-really-mean-it skips security prompts (which can be dangerous to set blindly because actions can lead to data loss or additional costs) +``` + +### SEE ALSO + +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities + diff --git a/docs/metalctl_size_reservations_list.md b/docs/metalctl_size_reservation_usage.md similarity index 85% rename from docs/metalctl_size_reservations_list.md rename to docs/metalctl_size_reservation_usage.md index 13f8c8ad..39a23157 100644 --- a/docs/metalctl_size_reservations_list.md +++ b/docs/metalctl_size_reservation_usage.md @@ -1,20 +1,19 @@ -## metalctl size reservations list +## metalctl size reservation usage -list size reservations +see current usage of size reservations ``` -metalctl size reservations list [flags] +metalctl size reservation usage [flags] ``` ### Options ``` - -h, --help help for list + -h, --help help for usage --partition string the partition to filter --project string the project to filter --size-id string the size-id to filter - --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: partition|project|size|tenant - --tenant string the tenant to filter + --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: amount|id|partition|project|size|used-amount ``` ### Options inherited from parent commands @@ -47,5 +46,5 @@ metalctl size reservations list [flags] ### SEE ALSO -* [metalctl size reservations](metalctl_size_reservations.md) - manage size reservations +* [metalctl size reservation](metalctl_size_reservation.md) - manage reservation entities diff --git a/go.mod b/go.mod index e9869f37..b421c625 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 - github.com/metal-stack/metal-go v0.35.0 - github.com/metal-stack/metal-lib v0.18.2 + github.com/metal-stack/metal-go v0.36.0 + github.com/metal-stack/metal-lib v0.18.3 github.com/metal-stack/updater v1.2.2 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.6-0.20230925090304-df64c4bbad77 @@ -32,25 +32,26 @@ require ( github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/avast/retry-go/v4 v4.6.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.24.0 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect + github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect github.com/aws/smithy-go v1.19.0 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cheggaaa/pb/v3 v3.1.5 // indirect - github.com/coreos/go-iptables v0.7.0 // indirect + github.com/coder/websocket v1.8.12 // indirect + github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/coreos/go-oidc/v3 v3.11.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect @@ -60,7 +61,9 @@ require ( github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gaissmai/bart v0.11.1 // indirect github.com/go-jose/go-jose/v4 v4.0.4 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -81,7 +84,7 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/go-github/v56 v56.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/nftables v0.2.0 // indirect + github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect github.com/gorilla/csrf v1.7.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect @@ -121,6 +124,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect @@ -131,16 +135,17 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tailscale/certstore v0.1.1-0.20231020161753-77811a65f4ff // indirect + github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect - github.com/tailscale/golang-x-crypto v0.0.0-20230713185742-f0b76a10a08e // indirect + github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 // indirect - github.com/tailscale/web-client-prebuilt v0.0.0-20231212225314-8b6b8ae622f2 // indirect - github.com/tailscale/wireguard-go v0.0.0-20231101022006-db7604d1aa90 // indirect + github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect + github.com/tailscale/wireguard-go v0.0.0-20240731203015-71393c576b98 // indirect github.com/tcnksm/go-httpstat v0.2.0 // indirect - github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect + github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect github.com/vishvananda/netlink v1.2.1-beta.2 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -155,7 +160,7 @@ require ( golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect @@ -168,10 +173,8 @@ require ( google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gvisor.dev/gvisor v0.0.0-20230928000133-4fe30062272c // indirect - inet.af/peercred v0.0.0-20210906144145-0893ea02156a // indirect - nhooyr.io/websocket v1.8.10 // indirect + gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/yaml v1.4.0 // indirect - tailscale.com v1.54.1 // indirect + tailscale.com v1.72.1 // indirect ) diff --git a/go.sum b/go.sum index 111e7447..e9634a3b 100644 --- a/go.sum +++ b/go.sum @@ -18,51 +18,53 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA= github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE= -github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= -github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= -github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= +github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= +github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.5 h1:lodGSevz7d+kkFJodfauThRxK9mdJbyutUxGq1NNhvw= +github.com/aws/aws-sdk-go-v2/config v1.26.5/go.mod h1:DxHrz6diQJOc9EwDslVRh84VjjrE17g+pVZXUeSxaDU= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= -github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5 h1:5SI5O2tMp/7E/FqhYnaKdxbWjlCi2yujjNI/UO725iU= -github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5/go.mod h1:uXndCJoDO9gpuK24rNWVCnrGNUydKFEAYAZ7UU9S0rQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= -github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= -github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= -github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= -github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= +github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -73,6 +75,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnN github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= +github.com/dsnet/try v0.0.3 h1:ptR59SsrcFUYbT/FhAbKTV6iLkeD6O18qfIWRml2fqI= +github.com/dsnet/try v0.0.3/go.mod h1:WBM8tRpUmnXXhY1U6/S8dt6UWdHTQ7y8A5YSkRCkq40= 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/emicklei/go-restful-openapi/v2 v2.10.2 h1:RfxWvGmASIwVoZIEncvXLi5HxYQ0S8rNBkPresDMt1c= @@ -88,10 +94,14 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc= +github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -131,7 +141,6 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -151,8 +160,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8= -github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= 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/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= @@ -173,6 +182,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20240227161007-c728f5dd21c8 h1:V3plQrMHRWOB5zMm3yNqvBxDQVW1+/wHBSok5uPdmVs= github.com/insomniacslk/dhcp v0.0.0-20240227161007-c728f5dd21c8/go.mod h1:izxuNQZeFrbx2nK2fAyN5iNUB34Fe9j0nK4PwLzAkKw= +github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= +github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -233,10 +244,10 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack/metal-go v0.35.0 h1:Ixj2iB3bc3jvveeCcSSdYosyt7nP2/3Mg6tf8Ks7YmU= -github.com/metal-stack/metal-go v0.35.0/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ= -github.com/metal-stack/metal-lib v0.18.2 h1:EAmZkZeKpenAvxZRSKsA6gj9Jd8XLR6Z0/QhABFCCDE= -github.com/metal-stack/metal-lib v0.18.2/go.mod h1:GJjipRpHmpd2vjBtsaw9gGk5ZFan7NlShyjIsTdY1x4= +github.com/metal-stack/metal-go v0.36.0 h1:U3J3rolrw/uU5J2V982UPoCm23U8/0oq/eq0oXiq81c= +github.com/metal-stack/metal-go v0.36.0/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ= +github.com/metal-stack/metal-lib v0.18.3 h1:bovFiJPB9SMvuGLqcXVWz6jFB8HrdzwnCX7TFlen4r0= +github.com/metal-stack/metal-lib v0.18.3/go.mod h1:Ctyi6zaXFr2NVrQZLFsDLnFCzupKnYErTtgRFKAsnbw= github.com/metal-stack/security v0.8.1 h1:4zmVUxZvDWShVvVIxM3XhIv7pTmPe9DvACRIHW6YTsk= github.com/metal-stack/security v0.8.1/go.mod h1:OO8ZilZO6fUV5QEmwc7HP/RAjqYrGQxXoYIddJ9TvqE= github.com/metal-stack/updater v1.2.2 h1:gnUrnQgfT20QFMDtFBY89opKoBAkdeI/8T2iwMHNdxs= @@ -270,6 +281,8 @@ github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Q github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= +github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= @@ -312,30 +325,36 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tailscale/certstore v0.1.1-0.20231020161753-77811a65f4ff h1:vnxdYZUJbsSRcIcduDW3DcQqfqaiv4FUgy25q8X+vfI= -github.com/tailscale/certstore v0.1.1-0.20231020161753-77811a65f4ff/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= -github.com/tailscale/golang-x-crypto v0.0.0-20230713185742-f0b76a10a08e h1:JyeJF/HuSwvxWtsR1c0oKX1lzaSH5Wh4aX+MgiStaGQ= -github.com/tailscale/golang-x-crypto v0.0.0-20230713185742-f0b76a10a08e/go.mod h1:DjoeCULdP6vTJ/xY+nzzR9LaUHprkbZEpNidX0aqEEk= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQSPhaUPjUQwozcRdDdSxxqhNgNZ3drZFk= github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= -github.com/tailscale/web-client-prebuilt v0.0.0-20231212225314-8b6b8ae622f2 h1:pBYcq0/U/KBtWUoeF4EUZSl7Zxgf/NKwL7VjFTwhzTI= -github.com/tailscale/web-client-prebuilt v0.0.0-20231212225314-8b6b8ae622f2/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= -github.com/tailscale/wireguard-go v0.0.0-20231101022006-db7604d1aa90 h1:lMGYrokOq9NKDw1UMBH7AsS4boZ41jcduvYaRIdedhE= -github.com/tailscale/wireguard-go v0.0.0-20231101022006-db7604d1aa90/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M= +github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y= +github.com/tailscale/wireguard-go v0.0.0-20240731203015-71393c576b98 h1:RNpJrXfI5u6e+uzyIzvmnXbhmhdRkVf//90sMBH3lso= +github.com/tailscale/wireguard-go v0.0.0-20240731203015-71393c576b98/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= +github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek= +github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg= github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= -github.com/u-root/u-root v0.11.0 h1:6gCZLOeRyevw7gbTwMj3fKxnr9+yHFlgF3N7udUVNO8= -github.com/u-root/u-root v0.11.0/go.mod h1:DBkDtiZyONk9hzVEdB/PWI9B4TxDkElWlVTHseglrZY= -github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= -github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs= +github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/undefinedlabs/go-mpatch v1.0.7 h1:943FMskd9oqfbZV0qRVKOUsXQhTLXL0bQTVbQSpzmBs= github.com/undefinedlabs/go-mpatch v1.0.7/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= @@ -365,22 +384,21 @@ golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= -golang.org/x/exp/typeparams v0.0.0-20230905200255-921286631fa9 h1:j3D9DvWRpUfIyFfDPws7LoIZ2MAI1OJHdQXtTnYtN+k= -golang.org/x/exp/typeparams v0.0.0-20230905200255-921286631fa9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= -golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= +golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a h1:8qmSSA8Gz/1kTrCe0nqR0R3Gb/NDhykzWw2q2mWZydM= +golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -423,25 +441,19 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gvisor.dev/gvisor v0.0.0-20230928000133-4fe30062272c h1:bYb98Ra11fJ8F2xFbZx0zg2VQ28lYqC1JxfaaF53xqY= -gvisor.dev/gvisor v0.0.0-20230928000133-4fe30062272c/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY= +gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 h1:TU8z2Lh3Bbq77w0t1eG8yRlLcNHzZu3x6mhoH2Mk0c8= +gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU= honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8= honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -inet.af/peercred v0.0.0-20210906144145-0893ea02156a h1:qdkS8Q5/i10xU2ArJMKYhVa1DORzBfYS/qA2UK2jheg= -inet.af/peercred v0.0.0-20210906144145-0893ea02156a/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU= -inet.af/wf v0.0.0-20221017222439-36129f591884 h1:zg9snq3Cpy50lWuVqDYM7AIRVTtU50y5WXETMFohW/Q= -inet.af/wf v0.0.0-20221017222439-36129f591884/go.mod h1:bSAQ38BYbY68uwpasXOTZo22dKGy9SNvI6PZFeKomZE= k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= -nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -software.sslmate.com/src/go-pkcs12 v0.2.1 h1:tbT1jjaeFOF230tzOIRJ6U5S1jNqpsSyNjzDd58H3J8= -software.sslmate.com/src/go-pkcs12 v0.2.1/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.54.1 h1:YBY6789Fo7dKS8s51YLvs/dwOMtsv2howVa/iZGRKcg= -tailscale.com v1.54.1/go.mod h1:MnLFoCRwzFWr3qtkSW2nZdQpK7wQRZEk1KtcEGAuZYw= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +tailscale.com v1.72.1 h1:hk82jek36ph2S3Tfsh57NVWKEm/pZ9nfUonvlowpfaA= +tailscale.com v1.72.1/go.mod h1:v7OHtg0KLAnhOVf81Z8WrjNefj238QbFhgkWJQoKxbs=