Skip to content

Commit

Permalink
Dualstack Support
Browse files Browse the repository at this point in the history
  • Loading branch information
majst01 committed Aug 2, 2024
1 parent dfe9cef commit 6d903e2
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 54 deletions.
5 changes: 5 additions & 0 deletions cmd/completion/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package completion

import (
"github.com/metal-stack/metal-go/api/client/ip"
"github.com/metal-stack/metal-go/api/models"
"github.com/spf13/cobra"
)

Expand All @@ -16,3 +17,7 @@ func (c *Completion) IpListCompletion(cmd *cobra.Command, args []string, toCompl
}
return names, cobra.ShellCompDirectiveNoFileComp
}

func (c *Completion) IPAddressFamilyCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{models.V1IPAllocateRequestAddressfamilyIPV4, models.V1IPAllocateRequestAddressfamilyIPV6}, cobra.ShellCompDirectiveNoFileComp
}
4 changes: 2 additions & 2 deletions cmd/completion/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ func (c *Completion) NetworkDestinationPrefixesCompletion(cmd *cobra.Command, ar
}
return prefixes, cobra.ShellCompDirectiveNoFileComp
}
func (c *Completion) AddressFamilyCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{models.V1NetworkImmutableAddressfamilyIPV4, models.V1NetworkImmutableAddressfamilyIPV6}, cobra.ShellCompDirectiveNoFileComp
func (c *Completion) NetworkAddressFamilyCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{models.V1NetworkAllocateRequestAddressfamilyIPV4, models.V1NetworkAllocateRequestAddressfamilyIPV6}, cobra.ShellCompDirectiveNoFileComp
}
59 changes: 47 additions & 12 deletions cmd/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"
"fmt"
"net/netip"
"strings"

"github.com/metal-stack/metal-go/api/client/ip"
Expand Down Expand Up @@ -49,9 +50,11 @@ func newIPCmd(c *config) *cobra.Command {
cmd.Flags().StringP("network", "", "", "network from where the IP should be allocated.")
cmd.Flags().StringP("project", "", "", "project for which the IP should be allocated.")
cmd.Flags().StringSliceP("tags", "", nil, "tags to attach to the IP.")
cmd.Flags().StringP("addressfamily", "", "", "addressfamily of the ip to acquire, defaults to IPv4 [optional]")
genericcli.Must(cmd.RegisterFlagCompletionFunc("network", c.comp.NetworkListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("type", cobra.FixedCompletions([]string{models.V1IPAllocateRequestTypeEphemeral, models.V1IPAllocateRequestTypeStatic}, cobra.ShellCompDirectiveNoFileComp)))
genericcli.Must(cmd.RegisterFlagCompletionFunc("addressfamily", c.comp.IPAddressFamilyCompletion))
},
ListCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().StringP("ipaddress", "", "", "ipaddress to filter [optional]")
Expand All @@ -62,11 +65,13 @@ func newIPCmd(c *config) *cobra.Command {
cmd.Flags().StringP("network", "", "", "network to filter [optional]")
cmd.Flags().StringP("name", "", "", "name to filter [optional]")
cmd.Flags().StringSliceP("tags", "", nil, "tags to filter [optional]")
cmd.Flags().StringP("addressfamily", "", "", "addressfamily of the ip to filter, defaults to all addressfamilies [optional]")
genericcli.Must(cmd.RegisterFlagCompletionFunc("ipaddress", c.comp.IpListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("network", c.comp.NetworkListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("type", cobra.FixedCompletions([]string{models.V1IPAllocateRequestTypeEphemeral, models.V1IPAllocateRequestTypeStatic}, cobra.ShellCompDirectiveNoFileComp)))
genericcli.Must(cmd.RegisterFlagCompletionFunc("machineid", c.comp.MachineListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("addressfamily", c.comp.IPAddressFamilyCompletion))
},
DeleteCmdMutateFn: func(cmd *cobra.Command) {
cmd.Aliases = append(cmd.Aliases, "free")
Expand Down Expand Up @@ -110,6 +115,28 @@ func (c ipCmd) List() ([]*models.V1IPResponse, error) {
return nil, err
}

if viper.IsSet("addressfamily") {
af := viper.GetString("addressfamily")
var result []*models.V1IPResponse
for _, ipresp := range resp.Payload {
if ipresp == nil || ipresp.Ipaddress == nil {
continue
}
parsedIP, err := netip.ParseAddr(*ipresp.Ipaddress)
if err != nil {
return nil, err
}
if parsedIP.Is4() && af == models.V1IPAllocateRequestAddressfamilyIPV6 {
continue
}
if parsedIP.Is6() && af == models.V1IPAllocateRequestAddressfamilyIPV4 {
continue
}
result = append(result, ipresp)
}
return result, nil
}

return resp.Payload, nil
}

Expand Down Expand Up @@ -172,12 +199,13 @@ func ipResponseToCreate(r *models.V1IPResponse) *ipAllocateRequest {
return &ipAllocateRequest{
SpecificIP: ip,
V1IPAllocateRequest: &models.V1IPAllocateRequest{
Description: r.Description,
Name: r.Name,
Networkid: r.Networkid,
Projectid: r.Projectid,
Tags: r.Tags,
Type: r.Type,
Description: r.Description,
Name: r.Name,
Networkid: r.Networkid,
Projectid: r.Projectid,
Tags: r.Tags,
Type: r.Type,
Addressfamily: pointer.Pointer(models.V1IPAllocateRequestAddressfamilyIPV4),
},
}
}
Expand All @@ -193,15 +221,22 @@ func ipResponseToUpdate(r *models.V1IPResponse) *models.V1IPUpdateRequest {
}

func (c *ipCmd) createRequestFromCLI() (*ipAllocateRequest, error) {

var af *string
if viper.IsSet("addressfamily") {
af = pointer.Pointer(viper.GetString("addressfamily"))
}

return &ipAllocateRequest{
SpecificIP: viper.GetString("ipaddress"),
V1IPAllocateRequest: &models.V1IPAllocateRequest{
Description: viper.GetString("description"),
Name: viper.GetString("name"),
Networkid: pointer.Pointer(viper.GetString("network")),
Projectid: pointer.Pointer(viper.GetString("project")),
Type: pointer.Pointer(viper.GetString("type")),
Tags: viper.GetStringSlice("tags"),
Description: viper.GetString("description"),
Name: viper.GetString("name"),
Networkid: pointer.Pointer(viper.GetString("network")),
Projectid: pointer.Pointer(viper.GetString("project")),
Type: pointer.Pointer(viper.GetString("type")),
Tags: viper.GetStringSlice("tags"),
Addressfamily: af,
},
}, nil
}
Expand Down
1 change: 1 addition & 0 deletions cmd/ip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ IP ALLOCATION UUID DESCRIPTION NAME NETWORK PROJECT TYPE
"--project", *want.Projectid,
"--type", *want.Type,
"--tags", strings.Join(want.Tags, ","),
"--addressfamily", models.V1IPAllocateRequestAddressfamilyIPV4,
}
assertExhaustiveArgs(t, args, commonExcludedFileArgs()...)
return args
Expand Down
18 changes: 11 additions & 7 deletions cmd/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func newNetworkCmd(c *config) *cobra.Command {
cmd.Flags().String("addressfamily", "", "addressfamily to filter, either ipv4 or ipv6 [optional]")
genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("addressfamily", c.comp.AddressFamilyCompletion))
genericcli.Must(cmd.RegisterFlagCompletionFunc("addressfamily", c.comp.NetworkAddressFamilyCompletion))
},
UpdateCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("name", "", "the name of the network [optional]")
Expand Down Expand Up @@ -107,10 +107,13 @@ func newNetworkCmd(c *config) *cobra.Command {

var (
af *string
length *int64
length = make(map[string]int64)
)
if viper.IsSet("length") {
length = pointer.Pointer(viper.GetInt64("length"))
if viper.IsSet("ipv4length") {
length[models.V1IPAllocateRequestAddressfamilyIPV4] = viper.GetInt64("ipv4length")
}
if viper.IsSet("ipv6length") {
length[models.V1IPAllocateRequestAddressfamilyIPV6] = viper.GetInt64("ipv6length")
}
if viper.IsSet("addressfamily") {
af = pointer.Pointer(viper.GetString("addressfamily"))
Expand All @@ -125,7 +128,7 @@ func newNetworkCmd(c *config) *cobra.Command {
Labels: labels,
Destinationprefixes: destinationPrefixes,
Nat: nat,
AddressFamily: af,
Addressfamily: af,
Length: length,
}, c.describePrinter)
}
Expand Down Expand Up @@ -156,9 +159,11 @@ func newNetworkCmd(c *config) *cobra.Command {
allocateCmd.Flags().BoolP("dmz", "", false, "use this private network as dmz. [optional]")
allocateCmd.Flags().BoolP("shared", "", false, "shared allows usage of this private network from other networks")
allocateCmd.Flags().StringP("addressfamily", "", "ipv4", "addressfamily of the network to acquire [optional]")
allocateCmd.Flags().Int64P("length", "", 22, "bitlength of network to create. [optional]")
allocateCmd.Flags().Int64P("ipv4length", "", 22, "ipv4 bitlength of network to create. [optional]")
allocateCmd.Flags().Int64P("ipv6length", "", 64, "ip6 bitlength of network to create. [optional]")
genericcli.Must(allocateCmd.RegisterFlagCompletionFunc("project", c.comp.ProjectListCompletion))
genericcli.Must(allocateCmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion))
genericcli.Must(allocateCmd.RegisterFlagCompletionFunc("addressfamily", c.comp.NetworkAddressFamilyCompletion))

genericcli.Must(allocateCmd.MarkFlagRequired("name"))
genericcli.Must(allocateCmd.MarkFlagRequired("project"))
Expand Down Expand Up @@ -194,7 +199,6 @@ func (c networkCmd) List() ([]*models.V1NetworkResponse, error) {
Prefixes: viper.GetStringSlice("prefixes"),
Destinationprefixes: viper.GetStringSlice("destination-prefixes"),
Parentnetworkid: viper.GetString("parent"),
Addressfamily: viper.GetString("addressfamily"),
}), nil)
if err != nil {
return nil, err
Expand Down
32 changes: 16 additions & 16 deletions cmd/tableprinters/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,29 @@ func addNetwork(prefix string, n *models.V1NetworkResponse, wide bool) []string
}
privateSuper := fmt.Sprintf("%t", flag)
nat := fmt.Sprintf("%t", *n.Nat)

usage := fmt.Sprintf("IPs: %v/%v", *n.Usage.UsedIps, *n.Usage.AvailableIps)

ipUse := float64(*n.Usage.UsedIps) / float64(*n.Usage.AvailableIps)
shortIPUsage := nbr
if ipUse >= 0.9 {
shortIPUsage += color.RedString(dot)
} else if ipUse >= 0.7 {
shortIPUsage += color.YellowString(dot)
// FIXME add ipv6 usage
ipv4usage := fmt.Sprintf("IPs: %v/%v", *n.Usage.UsedIps, *n.Usage.AvailableIps)

ipv4Use := float64(*n.Usage.UsedIps) / float64(*n.Usage.AvailableIps)
shortIPv4IPUsage := nbr
if ipv4Use >= 0.9 {
shortIPv4IPUsage += color.RedString(dot)
} else if ipv4Use >= 0.7 {
shortIPv4IPUsage += color.YellowString(dot)
} else {
shortIPUsage += color.GreenString(dot)
shortIPv4IPUsage += color.GreenString(dot)
}

shortPrefixUsage := ""
shortIPv4PrefixUsage := ""
if *n.Usage.AvailablePrefixes > 0 {
prefixUse := float64(*n.Usage.UsedPrefixes) / float64(*n.Usage.AvailablePrefixes)
if prefixUse >= 0.9 {
shortPrefixUsage = color.RedString(dot)
shortIPv4PrefixUsage = color.RedString(dot)
}
usage = fmt.Sprintf("%s\nPrefixes:%d/%d", usage, *n.Usage.UsedPrefixes, *n.Usage.AvailablePrefixes)
ipv4usage = fmt.Sprintf("%s\nPrefixes:%d/%d", ipv4usage, *n.Usage.UsedPrefixes, *n.Usage.AvailablePrefixes)
}

max := getMaxLineCount(n.Description, n.Name, n.Projectid, n.Partitionid, nat, prefixes, usage, privateSuper)
max := getMaxLineCount(n.Description, n.Name, n.Projectid, n.Partitionid, nat, prefixes, ipv4usage, privateSuper)
for i := 0; i < max-1; i++ {
id += "\n│"
}
Expand All @@ -102,9 +102,9 @@ func addNetwork(prefix string, n *models.V1NetworkResponse, wide bool) []string
annotations := strings.Join(as, "\n")

if wide {
return []string{id, n.Description, n.Name, n.Projectid, n.Partitionid, nat, shared, prefixes, usage, privateSuper, annotations}
return []string{id, n.Description, n.Name, n.Projectid, n.Partitionid, nat, shared, prefixes, ipv4usage, privateSuper, annotations}
} else {
return []string{id, n.Name, n.Projectid, n.Partitionid, nat, shared, prefixes, shortPrefixUsage, shortIPUsage}
return []string{id, n.Name, n.Projectid, n.Partitionid, nat, shared, prefixes, shortIPv4PrefixUsage, shortIPv4IPUsage}
}
}

Expand Down
3 changes: 2 additions & 1 deletion docs/metalctl_network_allocate.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ metalctl network allocate [flags]
-d, --description string description of the network to create. [optional]
--dmz use this private network as dmz. [optional]
-h, --help help for allocate
--ipv4length int ipv4 bitlength of network to create. [optional] (default 22)
--ipv6length int ip6 bitlength of network to create. [optional] (default 64)
--labels strings labels for this network. [optional]
--length int bitlength of network to create. [optional] (default 22)
-n, --name string name of the network to create. [required]
--partition string partition where this network should exist. [required]
--project string partition where this network should exist. [required]
Expand Down
1 change: 1 addition & 0 deletions docs/metalctl_network_ip_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ metalctl network ip create [flags]
### Options

```
--addressfamily string addressfamily of the ip to acquire, defaults to IPv4 [optional]
--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.
-d, --description string description of the IP to allocate. [optional]
-f, --file string filename of the create or update request in yaml format, or - for stdin.
Expand Down
21 changes: 11 additions & 10 deletions docs/metalctl_network_ip_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ metalctl network ip list [flags]
### Options

```
-h, --help help for list
--ipaddress string ipaddress to filter [optional]
--machineid string machineid to filter [optional]
--name string name to filter [optional]
--network string network to filter [optional]
--prefix string prefix to filter [optional]
--project string project to filter [optional]
--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: description|id|ipaddress|name|network|type
--tags strings tags to filter [optional]
--type string type to filter [optional]
--addressfamily string addressfamily of the ip to filter, defaults to all addressfamilies [optional]
-h, --help help for list
--ipaddress string ipaddress to filter [optional]
--machineid string machineid to filter [optional]
--name string name to filter [optional]
--network string network to filter [optional]
--prefix string prefix to filter [optional]
--project string project to filter [optional]
--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: description|id|ipaddress|name|network|type
--tags strings tags to filter [optional]
--type string type to filter [optional]
```

### Options inherited from parent commands
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.32.2-0.20240711103636-2b8da1b20985
github.com/metal-stack/metal-lib v0.17.1
github.com/metal-stack/metal-go v0.32.3-0.20240725054241-040df42094d5
github.com/metal-stack/metal-lib v0.17.2
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
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,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.32.2-0.20240711103636-2b8da1b20985 h1:pUAez+Jc8XqJkaxBb6OPZeDECrvx8M6N89jgW7FjtYY=
github.com/metal-stack/metal-go v0.32.2-0.20240711103636-2b8da1b20985/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ=
github.com/metal-stack/metal-lib v0.17.1 h1:JLa4wJ62dgxtY9UOLF+QDk10/i/W5vhzrv8RsundDUY=
github.com/metal-stack/metal-lib v0.17.1/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s=
github.com/metal-stack/metal-go v0.32.3-0.20240725054241-040df42094d5 h1:cCX6wyczMdTtMrupE7vRUFmE1pZQ2XVYjzRmPoT+/3Y=
github.com/metal-stack/metal-go v0.32.3-0.20240725054241-040df42094d5/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ=
github.com/metal-stack/metal-lib v0.17.2 h1:T1rxCPgagHW/M0wWSrOj4hWsPZMSt1pYw90Z3vBm88Q=
github.com/metal-stack/metal-lib v0.17.2/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s=
github.com/metal-stack/security v0.8.0 h1:tVaSDB9m5clwYrnLyaXfPy7mQlJTnmeoHscG+RUy/xo=
github.com/metal-stack/security v0.8.0/go.mod h1:7GAcQb+pOgflW30ohJygxpqc3i0dQ2ahGJK1CU5tqa0=
github.com/metal-stack/updater v1.2.2 h1:gnUrnQgfT20QFMDtFBY89opKoBAkdeI/8T2iwMHNdxs=
Expand Down

0 comments on commit 6d903e2

Please sign in to comment.