diff --git a/cmd/project-reservations.go b/cmd/project-reservations.go index 299bfae..0548933 100644 --- a/cmd/project-reservations.go +++ b/cmd/project-reservations.go @@ -2,7 +2,6 @@ package cmd import ( "errors" - "fmt" "github.com/fi-ts/cloud-go/api/client/project" "github.com/fi-ts/cloud-go/api/models" @@ -24,16 +23,15 @@ func newMachineReservationsCmd(c *config) *cobra.Command { } cmdsConfig := &genericcli.CmdsConfig[*models.V1MachineReservationCreateRequest, *models.V1MachineReservationUpdateRequest, *models.V1MachineReservationResponse]{ - BinaryName: binaryName, - MultiArgGenericCLI: genericcli.NewGenericMultiArgCLI(w).WithFS(c.fs), - Args: []string{"project", "size"}, - Singular: "machine-reservation", - Plural: "machine-reservations", - Description: "manage machine reservations, ids must be provided in the form @", - Sorter: sorters.MachineReservationsSorter(), - ValidArgsFn: c.comp.MachineReservationListCompletion, - DescribePrinter: func() printers.Printer { return c.describePrinter }, - ListPrinter: func() printers.Printer { return c.listPrinter }, + BinaryName: binaryName, + GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.fs), + Singular: "machine-reservation", + Plural: "machine-reservations", + Description: "manage machine reservations, ids must be provided in the form @", + Sorter: sorters.MachineReservationsSorter(), + ValidArgsFn: c.comp.MachineReservationListCompletion, + DescribePrinter: func() printers.Printer { return c.describePrinter }, + ListPrinter: func() printers.Printer { return c.listPrinter }, ListCmdMutateFn: func(cmd *cobra.Command) { cmd.Flags().String("project", "", "show reservations of given project") cmd.Flags().String("size", "", "show reservations of given size") @@ -73,17 +71,16 @@ func newMachineReservationsCmd(c *config) *cobra.Command { }, nil }, UpdateRequestFromCLI: func(args []string) (*models.V1MachineReservationUpdateRequest, error) { - ids, err := genericcli.GetExactlyNArgs(2, args) + id, err := genericcli.GetExactlyOneArg(args) if err != nil { return nil, err } return &models.V1MachineReservationUpdateRequest{ + ID: &id, Amount: pointer.PointerOrNil(viper.GetInt32("amount")), Description: pointer.PointerOrNil(viper.GetString("description")), Partitionids: viper.GetStringSlice("partitions"), - Projectid: &ids[w.projectIndex()], - Sizeid: &ids[w.sizeIndex()], }, nil }, } @@ -108,8 +105,11 @@ func newMachineReservationsCmd(c *config) *cobra.Command { return genericcli.NewCmds(cmdsConfig, usageCmd) } -func (m machineReservationsCmd) Convert(r *models.V1MachineReservationResponse) ([]string, *models.V1MachineReservationCreateRequest, *models.V1MachineReservationUpdateRequest, error) { - return []string{*r.Projectid, *r.Sizeid}, toMachineReservationCreateRequest(r), toMachineReservationUpdateRequest(r), nil +func (m machineReservationsCmd) Convert(r *models.V1MachineReservationResponse) (string, *models.V1MachineReservationCreateRequest, *models.V1MachineReservationUpdateRequest, error) { + if r.ID == nil { + return "", nil, nil, errors.New("id is not defined") + } + return *r.ID, toMachineReservationCreateRequest(r), toMachineReservationUpdateRequest(r), nil } func toMachineReservationCreateRequest(r *models.V1MachineReservationResponse) *models.V1MachineReservationCreateRequest { @@ -147,10 +147,8 @@ func (m machineReservationsCmd) Create(rq *models.V1MachineReservationCreateRequ return resp.Payload, nil } -func (m machineReservationsCmd) Delete(id ...string) (*models.V1MachineReservationResponse, error) { - resp, err := m.cloud.Project.DeleteMachineReservation(project.NewDeleteMachineReservationParams(). - WithProject(pointer.Pointer(id[m.projectIndex()])). - WithSize(pointer.Pointer(id[m.sizeIndex()])), nil) +func (m machineReservationsCmd) Delete(id string) (*models.V1MachineReservationResponse, error) { + resp, err := m.cloud.Project.DeleteMachineReservation(project.NewDeleteMachineReservationParams().WithID(id), nil) if err != nil { return nil, err } @@ -158,24 +156,13 @@ func (m machineReservationsCmd) Delete(id ...string) (*models.V1MachineReservati return resp.Payload, nil } -func (m machineReservationsCmd) Get(id ...string) (*models.V1MachineReservationResponse, error) { - all, err := m.List() +func (m machineReservationsCmd) Get(id string) (*models.V1MachineReservationResponse, error) { + resp, err := m.cloud.Project.GetMachineReservation(project.NewGetMachineReservationParams().WithID(id), nil) if err != nil { - return nil, fmt.Errorf("unable to fetch machine reservations: %w", err) - } - - for _, rv := range all { - if id[m.projectIndex()] != pointer.SafeDeref(rv.Projectid) { - continue - } - if id[m.sizeIndex()] != pointer.SafeDeref(rv.Sizeid) { - continue - } - - return rv, nil + return nil, err } - return nil, fmt.Errorf("no reservation found with size %q for project %q", id[m.sizeIndex()], id[m.projectIndex()]) + return resp.Payload, nil } func (m machineReservationsCmd) List() ([]*models.V1MachineReservationResponse, error) { @@ -220,10 +207,3 @@ func (m machineReservationsCmd) machineReservationsUsage() error { return m.listPrinter.Print(resp.Payload) } - -func (m machineReservationsCmd) projectIndex() int { - return 0 -} -func (m machineReservationsCmd) sizeIndex() int { - return 1 -} diff --git a/cmd/project-reservations_test.go b/cmd/project-reservations_test.go index 585b9ec..854dc10 100644 --- a/cmd/project-reservations_test.go +++ b/cmd/project-reservations_test.go @@ -17,6 +17,7 @@ import ( var ( machineReservation1 = &models.V1MachineReservationResponse{ + ID: pointer.Pointer("1"), Amount: pointer.Pointer(int32(3)), Description: "for firewalls", Labels: map[string]string{ @@ -29,6 +30,7 @@ var ( Tenant: pointer.Pointer("fits"), } machineReservation2 = &models.V1MachineReservationResponse{ + ID: pointer.Pointer("2"), Amount: pointer.Pointer(int32(3)), Description: "for machines", Labels: map[string]string{ @@ -63,15 +65,15 @@ func Test_ProjectMachineReservationsCmd_MultiResult(t *testing.T) { machineReservation2, }, wantTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION -fits project-a size-a 3 partition-a for firewalls -fits project-b size-b 3 partition-a,partition-b for machines +ID TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION +1 fits project-a size-a 3 partition-a for firewalls +2 fits project-b size-b 3 partition-a,partition-b for machines `), wantWideTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION LABELS -fits project-a size-a 3 partition-a for firewalls for firewalls size.metal-stack.io/reserved-at=2024-09-19T08:57:40Z - size.metal-stack.io/reserved-by=fits -fits project-b size-b 3 partition-a,partition-b for machines for machines size.metal-stack.io/reserved-by=fits +ID TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION LABELS +1 fits project-a size-a 3 partition-a for firewalls for firewalls size.metal-stack.io/reserved-at=2024-09-19T08:57:40Z + size.metal-stack.io/reserved-by=fits +2 fits project-b size-b 3 partition-a,partition-b for machines for machines size.metal-stack.io/reserved-by=fits `), template: pointer.Pointer("{{ .sizeid }} {{ .projectid }}"), wantTemplate: pointer.Pointer(` @@ -79,10 +81,10 @@ size-a project-a size-b project-b `), wantMarkdown: pointer.Pointer(` -| TENANT | PROJECT | SIZE | AMOUNT | PARTITIONS | DESCRIPTION | -|--------|-----------|--------|--------|-------------------------|---------------| -| fits | project-a | size-a | 3 | partition-a | for firewalls | -| fits | project-b | size-b | 3 | partition-a,partition-b | for machines | +| ID | TENANT | PROJECT | SIZE | AMOUNT | PARTITIONS | DESCRIPTION | +|----|--------|-----------|--------|--------|-------------------------|---------------| +| 1 | fits | project-a | size-a | 3 | partition-a | for firewalls | +| 2 | fits | project-b | size-b | 3 | partition-a,partition-b | for machines | `), }, { @@ -108,25 +110,6 @@ size-b project-b want: []*models.V1MachineReservationResponse{ machineReservation1, }, - wantTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION -fits project-a size-a 3 partition-a for firewalls - `), - wantWideTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION LABELS -fits project-a size-a 3 partition-a for firewalls for firewalls size.metal-stack.io/reserved-at=2024-09-19T08:57:40Z - size.metal-stack.io/reserved-by=fits - - `), - template: pointer.Pointer("{{ .sizeid }} {{ .projectid }}"), - wantTemplate: pointer.Pointer(` -size-a project-a - `), - wantMarkdown: pointer.Pointer(` -| TENANT | PROJECT | SIZE | AMOUNT | PARTITIONS | DESCRIPTION | -|--------|-----------|--------|--------|-------------|---------------| -| fits | project-a | size-a | 3 | partition-a | for firewalls | - `), }, { name: "apply", @@ -203,8 +186,7 @@ size-a project-a }, mocks: &testclient.CloudMockFns{ Project: func(mock *mock.Mock) { - mock.On("DeleteMachineReservation", testcommon.MatchIgnoreContext(t, project.NewDeleteMachineReservationParams(). - WithProject(machineReservation1.Projectid).WithSize(machineReservation1.Sizeid)), nil). + mock.On("DeleteMachineReservation", testcommon.MatchIgnoreContext(t, project.NewDeleteMachineReservationParams().WithID(*machineReservation1.ID)), nil). Return(&project.DeleteMachineReservationOK{Payload: machineReservation1}, nil) }, }, @@ -223,47 +205,43 @@ func Test_ProjectMachineReservationsCmd_SingleResult(t *testing.T) { { name: "describe", cmd: func(want *models.V1MachineReservationResponse) []string { - return []string{"project", "machine-reservation", "describe", *want.Projectid, *want.Sizeid} + return []string{"project", "machine-reservation", "describe", *want.ID} }, mocks: &testclient.CloudMockFns{ Project: func(mock *mock.Mock) { - mock.On("ListMachineReservations", testcommon.MatchIgnoreContext(t, project.NewListMachineReservationsParams().WithBody(&models.V1MachineReservationFindRequest{})), nil).Return(&project.ListMachineReservationsOK{ - Payload: []*models.V1MachineReservationResponse{ - machineReservation2, - machineReservation1, - }, + mock.On("GetMachineReservation", testcommon.MatchIgnoreContext(t, project.NewGetMachineReservationParams().WithID(*machineReservation1.ID)), nil).Return(&project.GetMachineReservationOK{ + Payload: machineReservation1, }, nil) }, }, want: machineReservation1, wantTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION -fits project-a size-a 3 partition-a for firewalls +ID TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION +1 fits project-a size-a 3 partition-a for firewalls `), wantWideTable: pointer.Pointer(` -TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION LABELS -fits project-a size-a 3 partition-a for firewalls for firewalls size.metal-stack.io/reserved-at=2024-09-19T08:57:40Z - size.metal-stack.io/reserved-by=fits +ID TENANT PROJECT SIZE AMOUNT PARTITIONS DESCRIPTION LABELS +1 fits project-a size-a 3 partition-a for firewalls for firewalls size.metal-stack.io/reserved-at=2024-09-19T08:57:40Z + size.metal-stack.io/reserved-by=fits `), template: pointer.Pointer("{{ .sizeid }} {{ .projectid }}"), wantTemplate: pointer.Pointer(` size-a project-a `), wantMarkdown: pointer.Pointer(` -| TENANT | PROJECT | SIZE | AMOUNT | PARTITIONS | DESCRIPTION | -|--------|-----------|--------|--------|-------------|---------------| -| fits | project-a | size-a | 3 | partition-a | for firewalls | +| ID | TENANT | PROJECT | SIZE | AMOUNT | PARTITIONS | DESCRIPTION | +|----|--------|-----------|--------|--------|-------------|---------------| +| 1 | fits | project-a | size-a | 3 | partition-a | for firewalls | `), }, { name: "delete", cmd: func(want *models.V1MachineReservationResponse) []string { - return []string{"project", "machine-reservation", "rm", *want.Projectid, *want.Sizeid} + return []string{"project", "machine-reservation", "rm", *want.ID} }, mocks: &testclient.CloudMockFns{ Project: func(mock *mock.Mock) { - mock.On("DeleteMachineReservation", testcommon.MatchIgnoreContext(t, project.NewDeleteMachineReservationParams(). - WithProject(machineReservation1.Projectid).WithSize(machineReservation1.Sizeid)), nil). + mock.On("DeleteMachineReservation", testcommon.MatchIgnoreContext(t, project.NewDeleteMachineReservationParams().WithID(*machineReservation1.ID)), nil). Return(&project.DeleteMachineReservationOK{Payload: machineReservation1}, nil) }, }, diff --git a/cmd/sorters/project-reservations.go b/cmd/sorters/project-reservations.go index 7e9598a..db29ba8 100644 --- a/cmd/sorters/project-reservations.go +++ b/cmd/sorters/project-reservations.go @@ -8,6 +8,9 @@ import ( func MachineReservationsSorter() *multisort.Sorter[*models.V1MachineReservationResponse] { return multisort.New(multisort.FieldMap[*models.V1MachineReservationResponse]{ + "id": func(a, b *models.V1MachineReservationResponse, descending bool) multisort.CompareResult { + return multisort.Compare(p.SafeDeref(a.ID), p.SafeDeref(b.ID), descending) + }, "tenant": func(a, b *models.V1MachineReservationResponse, descending bool) multisort.CompareResult { return multisort.Compare(p.SafeDeref(a.Tenant), p.SafeDeref(b.Tenant), descending) }, @@ -20,11 +23,14 @@ func MachineReservationsSorter() *multisort.Sorter[*models.V1MachineReservationR "amount": func(a, b *models.V1MachineReservationResponse, descending bool) multisort.CompareResult { return multisort.Compare(p.SafeDeref(a.Amount), p.SafeDeref(b.Amount), descending) }, - }, multisort.Keys{{ID: "tenant"}, {ID: "project"}, {ID: "size"}, {ID: "amount"}}) + }, multisort.Keys{{ID: "tenant"}, {ID: "project"}, {ID: "size"}, {ID: "id"}}) } func MachineReservationsUsageSorter() *multisort.Sorter[*models.V1MachineReservationUsageResponse] { return multisort.New(multisort.FieldMap[*models.V1MachineReservationUsageResponse]{ + "id": func(a, b *models.V1MachineReservationUsageResponse, descending bool) multisort.CompareResult { + return multisort.Compare(p.SafeDeref(a.ID), p.SafeDeref(b.ID), descending) + }, "tenant": func(a, b *models.V1MachineReservationUsageResponse, descending bool) multisort.CompareResult { return multisort.Compare(p.SafeDeref(a.Tenant), p.SafeDeref(b.Tenant), descending) }, @@ -43,5 +49,5 @@ func MachineReservationsUsageSorter() *multisort.Sorter[*models.V1MachineReserva "unused-reservations": func(a, b *models.V1MachineReservationUsageResponse, descending bool) multisort.CompareResult { return multisort.Compare(p.SafeDeref(a.Usedreservations), p.SafeDeref(b.Usedreservations), descending) }, - }, multisort.Keys{{ID: "tenant"}, {ID: "project"}, {ID: "partition"}, {ID: "size"}, {ID: "reservations"}}) + }, multisort.Keys{{ID: "tenant"}, {ID: "project"}, {ID: "partition"}, {ID: "size"}, {ID: "id"}}) } diff --git a/cmd/tableprinters/project-reservations.go b/cmd/tableprinters/project-reservations.go index e52ea8b..9db829d 100644 --- a/cmd/tableprinters/project-reservations.go +++ b/cmd/tableprinters/project-reservations.go @@ -14,7 +14,7 @@ import ( func (t *TablePrinter) MachineReservationsTable(data []*models.V1MachineReservationResponse, wide bool) ([]string, [][]string, error) { var ( - header = []string{"Tenant", "Project", "Size", "Amount", "Partitions", "Description"} + header = []string{"ID", "Tenant", "Project", "Size", "Amount", "Partitions", "Description"} rows [][]string ) @@ -26,6 +26,7 @@ func (t *TablePrinter) MachineReservationsTable(data []*models.V1MachineReservat sort.Strings(rv.Partitionids) row := []string{ + pointer.SafeDeref(rv.ID), pointer.SafeDeref(rv.Tenant), pointer.SafeDeref(rv.Projectid), pointer.SafeDeref(rv.Sizeid), diff --git a/go.mod b/go.mod index b5d630b..faa7f20 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.17.0 github.com/fi-ts/accounting-go v0.10.0 - github.com/fi-ts/cloud-go v0.28.1-0.20240919083529-3d0d03132578 + github.com/fi-ts/cloud-go v0.28.1-0.20240925082728-63ee8d3526bf github.com/gardener/gardener v1.91.0 github.com/gardener/machine-controller-manager v0.53.1 github.com/go-openapi/runtime v0.28.0 diff --git a/go.sum b/go.sum index 29d41cf..05eb43f 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,8 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fi-ts/accounting-go v0.10.0 h1:vbPgTWq1iicyBWFRajX0bawZ1ADbhKGuJyNEtXjpr08= github.com/fi-ts/accounting-go v0.10.0/go.mod h1:ARKouuFYUV44xUKytAlczpzoti/S+o+PnXCN5BQA6nQ= -github.com/fi-ts/cloud-go v0.28.1-0.20240919083529-3d0d03132578 h1:TS+trg3j7YOZJatONv97bg3uCKKu+FytwoWY1RLJB2s= -github.com/fi-ts/cloud-go v0.28.1-0.20240919083529-3d0d03132578/go.mod h1:pcGGl+M2OmtvwyuTEOimqSHrZngDotG69lmBzEbx6cc= +github.com/fi-ts/cloud-go v0.28.1-0.20240925082728-63ee8d3526bf h1:F+wEF712gk9zkviHOT57bP1mYWjmXwtuv0Y5fCPAqMo= +github.com/fi-ts/cloud-go v0.28.1-0.20240925082728-63ee8d3526bf/go.mod h1:pcGGl+M2OmtvwyuTEOimqSHrZngDotG69lmBzEbx6cc= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=