Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/admin/v2/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func AddCmds(cmd *cobra.Command, c *config.Config) {

adminCmd.AddCommand(newAuditCmd(c))
adminCmd.AddCommand(newComponentCmd(c))
adminCmd.AddCommand(newFilesystemCmd(c))
adminCmd.AddCommand(newImageCmd(c))
adminCmd.AddCommand(newIPCmd(c))
adminCmd.AddCommand(newMachineCmd(c))
Expand Down
196 changes: 196 additions & 0 deletions cmd/admin/v2/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package v2

import (
"fmt"

"github.com/metal-stack/api/go/errorutil"
adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2"
apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/cli/cmd/config"
"github.com/metal-stack/cli/cmd/sorters"
"github.com/metal-stack/cli/pkg/helpers"
"github.com/metal-stack/metal-lib/pkg/genericcli"
"github.com/metal-stack/metal-lib/pkg/genericcli/printers"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type filesystem struct {
c *config.Config
}

func newFilesystemCmd(c *config.Config) *cobra.Command {
w := &filesystem{
c: c,
}

cmdsConfig := &genericcli.CmdsConfig[*adminv2.FilesystemServiceCreateRequest, *adminv2.FilesystemServiceUpdateRequest, *apiv2.FilesystemLayout]{
BinaryName: config.BinaryName,
GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.Fs),
Singular: "filesystem",
Plural: "filesystems",
Description: "manage filesystem layouts which define how disks, raid arrays and volumes are set up on machines during installation",
Sorter: sorters.FilesystemSorter(),
DescribePrinter: func() printers.Printer { return c.DescribePrinter },
ListPrinter: func() printers.Printer { return c.ListPrinter },
ValidArgsFn: c.Completion.FilesystemLayout,
ListCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("id", "", "id of the filesystem layout to filter for")
},
}

matchCmd := &cobra.Command{
Use: "match",
Short: "matches a filesystem layout to a size and image or to a machine",
Long: `matches a filesystem layout either to a given size and image combination,
or checks whether a given filesystem layout matches a given machine.`,
RunE: func(cmd *cobra.Command, _ []string) error {
return w.match(cmd)
},
}
matchCmd.Flags().String("size", "", "machine size to match against a filesystem layout")
matchCmd.Flags().String("image", "", "machine image to match against a filesystem layout")
matchCmd.Flags().String("machine", "", "uuid of the machine to check against a filesystem layout")
matchCmd.Flags().String("id", "", "id of the filesystem layout to check against a machine")

genericcli.Must(matchCmd.RegisterFlagCompletionFunc("size", c.Completion.Size))
genericcli.Must(matchCmd.RegisterFlagCompletionFunc("image", c.Completion.Image))
genericcli.Must(matchCmd.RegisterFlagCompletionFunc("machine", c.Completion.Machine))
genericcli.Must(matchCmd.RegisterFlagCompletionFunc("id", c.Completion.FilesystemLayout))

return genericcli.NewCmds(cmdsConfig, matchCmd)
}

func (c *filesystem) Get(id string) (*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Apiv2().Filesystem().Get(ctx, &apiv2.FilesystemServiceGetRequest{
Id: id,
})
if err != nil {
return nil, fmt.Errorf("failed to get filesystem layout: %w", err)
}

return resp.FilesystemLayout, nil
}

func (c *filesystem) List() ([]*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Apiv2().Filesystem().List(ctx, &apiv2.FilesystemServiceListRequest{
Id: pointer.PointerOrNil(viper.GetString("id")),
})
if err != nil {
return nil, fmt.Errorf("failed to list filesystem layouts: %w", err)
}

return resp.FilesystemLayouts, nil
}

func (c *filesystem) Create(rq *adminv2.FilesystemServiceCreateRequest) (*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Adminv2().Filesystem().Create(ctx, rq)
if err != nil {
if errorutil.IsConflict(err) {
return nil, genericcli.AlreadyExistsError()
}

return nil, fmt.Errorf("failed to create filesystem layout: %w", err)
}

return resp.FilesystemLayout, nil
}

func (c *filesystem) Update(rq *adminv2.FilesystemServiceUpdateRequest) (*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Adminv2().Filesystem().Update(ctx, rq)
if err != nil {
return nil, fmt.Errorf("failed to update filesystem layout: %w", err)
}

return resp.FilesystemLayout, nil
}

func (c *filesystem) Delete(id string) (*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Adminv2().Filesystem().Delete(ctx, &adminv2.FilesystemServiceDeleteRequest{
Id: id,
})
if err != nil {
return nil, fmt.Errorf("failed to delete filesystem layout: %w", err)
}

return resp.FilesystemLayout, nil
}

func (c *filesystem) Convert(r *apiv2.FilesystemLayout) (string, *adminv2.FilesystemServiceCreateRequest, *adminv2.FilesystemServiceUpdateRequest, error) {
return r.Id,
&adminv2.FilesystemServiceCreateRequest{
FilesystemLayout: r,
},
&adminv2.FilesystemServiceUpdateRequest{
Id: r.Id,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly related to this PR but we forgot to add labels to this entity, all of them should have labels.

UpdateMeta: helpers.UpdateMetaFromMeta(r.Meta),
Name: r.Name,
Description: r.Description,
Filesystems: r.Filesystems,
Disks: r.Disks,
Raid: r.Raid,
VolumeGroups: r.VolumeGroups,
LogicalVolumes: r.LogicalVolumes,
Constraints: r.Constraints,
},
nil
}

func (w *filesystem) match(_ *cobra.Command) error {
var (
sizeSet = viper.IsSet("size")
imageSet = viper.IsSet("image")
machineSet = viper.IsSet("machine")
layoutSet = viper.IsSet("id")
req *adminv2.FilesystemServiceMatchRequest
)

switch {
case sizeSet && imageSet:
req = &adminv2.FilesystemServiceMatchRequest{
Match: &adminv2.FilesystemServiceMatchRequest_SizeAndImage{
SizeAndImage: &adminv2.MatchImageAndSize{
Size: viper.GetString("size"),
Image: viper.GetString("image"),
},
},
}
case machineSet && layoutSet:
req = &adminv2.FilesystemServiceMatchRequest{
Match: &adminv2.FilesystemServiceMatchRequest_MachineAndFilesystemlayout{
MachineAndFilesystemlayout: &adminv2.MatchMachineAndFilesystemLayout{
Machine: viper.GetString("machine"),
FilesystemLayout: viper.GetString("id"),
},
},
}
default:
return fmt.Errorf("either both --size and --image or both --machine and --id must be set")
}

ctx, cancel := w.c.NewRequestContext()
defer cancel()

resp, err := w.c.Client.Adminv2().Filesystem().Match(ctx, req)
if err != nil {
return fmt.Errorf("failed to match filesystem layout: %w", err)
}

return w.c.ListPrinter.Print(resp.FilesystemLayout)
}
1 change: 1 addition & 0 deletions cmd/api/v2/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

func AddCmds(cmd *cobra.Command, c *config.Config) {
cmd.AddCommand(newAuditCmd(c))
cmd.AddCommand(newFilesystemCmd(c))
cmd.AddCommand(newHealthCmd(c))
cmd.AddCommand(newImageCmd(c))
cmd.AddCommand(newIPCmd(c))
Expand Down
86 changes: 86 additions & 0 deletions cmd/api/v2/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package v2

import (
"fmt"

apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/cli/cmd/config"
"github.com/metal-stack/cli/cmd/sorters"
"github.com/metal-stack/metal-lib/pkg/genericcli"
"github.com/metal-stack/metal-lib/pkg/genericcli/printers"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type filesystem struct {
c *config.Config
}

func newFilesystemCmd(c *config.Config) *cobra.Command {
w := &filesystem{
c: c,
}

cmdsConfig := &genericcli.CmdsConfig[any, any, *apiv2.FilesystemLayout]{
BinaryName: config.BinaryName,
GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.Fs),
Singular: "filesystem",
Plural: "filesystems",
Description: "a filesystem layout defines how disks, raid arrays and volumes are set up on a machine during installation",
Sorter: sorters.FilesystemSorter(),
OnlyCmds: genericcli.OnlyCmds(genericcli.ListCmd, genericcli.DescribeCmd),
DescribePrinter: func() printers.Printer { return c.DescribePrinter },
ListPrinter: func() printers.Printer { return c.ListPrinter },
ValidArgsFn: c.Completion.FilesystemLayout,
ListCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("id", "", "id of the filesystem layout which should be listed")
},
}

return genericcli.NewCmds(cmdsConfig)
}

func (c *filesystem) Get(id string) (*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Apiv2().Filesystem().Get(ctx, &apiv2.FilesystemServiceGetRequest{
Id: id,
})
if err != nil {
return nil, fmt.Errorf("failed to get filesystem layout: %w", err)
}

return resp.FilesystemLayout, nil
}

func (c *filesystem) List() ([]*apiv2.FilesystemLayout, error) {
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Apiv2().Filesystem().List(ctx, &apiv2.FilesystemServiceListRequest{
Id: pointer.PointerOrNil(viper.GetString("id")),
})
if err != nil {
return nil, fmt.Errorf("failed to list filesystem layouts: %w", err)
}

return resp.FilesystemLayouts, nil
}

func (c *filesystem) Create(rq any) (*apiv2.FilesystemLayout, error) {
panic("unimplemented")
}

func (c *filesystem) Delete(id string) (*apiv2.FilesystemLayout, error) {
panic("unimplemented")
}

func (c *filesystem) Convert(r *apiv2.FilesystemLayout) (string, any, any, error) {
panic("unimplemented")
}

func (c *filesystem) Update(rq any) (*apiv2.FilesystemLayout, error) {
panic("unimplemented")
}
22 changes: 22 additions & 0 deletions cmd/completion/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package completion

import (
apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/spf13/cobra"
)

func (c *Completion) FilesystemLayout(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
resp, err := c.Client.Apiv2().Filesystem().List(cmd.Context(), &apiv2.FilesystemServiceListRequest{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

var names []string

for _, fsl := range resp.FilesystemLayouts {
names = append(names, fsl.Id+"\t"+pointer.SafeDeref(fsl.Name))
}

return names, cobra.ShellCompDirectiveNoFileComp
}
21 changes: 21 additions & 0 deletions cmd/sorters/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package sorters

import (
apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/metal-lib/pkg/multisort"
"github.com/metal-stack/metal-lib/pkg/pointer"
)

func FilesystemSorter() *multisort.Sorter[*apiv2.FilesystemLayout] {
return multisort.New(multisort.FieldMap[*apiv2.FilesystemLayout]{
"id": func(a, b *apiv2.FilesystemLayout, descending bool) multisort.CompareResult {
return multisort.Compare(a.Id, b.Id, descending)
},
"name": func(a, b *apiv2.FilesystemLayout, descending bool) multisort.CompareResult {
return multisort.Compare(pointer.SafeDeref(a.Name), pointer.SafeDeref(b.Name), descending)
},
"description": func(a, b *apiv2.FilesystemLayout, descending bool) multisort.CompareResult {
return multisort.Compare(pointer.SafeDeref(a.Description), pointer.SafeDeref(b.Description), descending)
},
}, multisort.Keys{{ID: "id"}, {ID: "name"}})
}
5 changes: 5 additions & 0 deletions cmd/tableprinters/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin
case []*apiv2.Component:
return t.ComponentTable(d, wide)

case *apiv2.FilesystemLayout:
return t.FilesystemTable(pointer.WrapInSlice(d), wide)
case []*apiv2.FilesystemLayout:
return t.FilesystemTable(d, wide)

case *apiv2.Network:
return t.NetworkTable(pointer.WrapInSlice(d), wide)
case []*apiv2.Network:
Expand Down
Loading
Loading