Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dualstack support #256

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
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
}
5 changes: 5 additions & 0 deletions cmd/completion/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package completion

import (
"github.com/metal-stack/metal-go/api/client/network"
"github.com/metal-stack/metal-go/api/models"

"github.com/spf13/cobra"
)

Expand All @@ -28,3 +30,6 @@ func (c *Completion) NetworkDestinationPrefixesCompletion(cmd *cobra.Command, ar
}
return prefixes, cobra.ShellCompDirectiveNoFileComp
}
func (c *Completion) NetworkAddressFamilyCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{models.V1NetworkAllocateRequestAddressfamilyIPV4, models.V1NetworkAllocateRequestAddressfamilyIPV6}, cobra.ShellCompDirectiveNoFileComp
}
60 changes: 48 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,29 @@ func (c ipCmd) List() ([]*models.V1IPResponse, error) {
return nil, err
}

// actually filtered client side because server side would require a reql filter for addressfamilies
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 +200,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 +222,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
23 changes: 23 additions & 0 deletions cmd/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ func newNetworkCmd(c *config) *cobra.Command {
cmd.Flags().Int64P("vrf", "", 0, "vrf to filter [optional]")
cmd.Flags().StringSlice("prefixes", []string{}, "prefixes to filter, use it like: --prefixes prefix1,prefix2.")
cmd.Flags().StringSlice("destination-prefixes", []string{}, "destination prefixes to filter, use it like: --destination-prefixes prefix1,prefix2.")
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.NetworkAddressFamilyCompletion))
},
UpdateCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("name", "", "the name of the network [optional]")
Expand Down Expand Up @@ -105,6 +107,20 @@ func newNetworkCmd(c *config) *cobra.Command {
return err
}

var (
af *string
length = make(map[string]int64)
)
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"))
}

return w.childCLI.CreateAndPrint(&models.V1NetworkAllocateRequest{
Description: viper.GetString("description"),
Name: viper.GetString("name"),
Expand All @@ -114,6 +130,8 @@ func newNetworkCmd(c *config) *cobra.Command {
Labels: labels,
Destinationprefixes: destinationPrefixes,
Nat: nat,
Addressfamily: af,
Length: length,
}, c.describePrinter)
}

Expand Down Expand Up @@ -142,8 +160,12 @@ func newNetworkCmd(c *config) *cobra.Command {
allocateCmd.Flags().StringSlice("labels", []string{}, "labels for this network. [optional]")
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("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 @@ -235,6 +257,7 @@ func networkResponseToCreate(r *models.V1NetworkResponse) *models.V1NetworkCreat
Nat: r.Nat,
Parentnetworkid: r.Parentnetworkid,
Partitionid: r.Partitionid,
Defaultchildprefixlength: r.Defaultchildprefixlength,
Prefixes: r.Prefixes,
Privatesuper: r.Privatesuper,
Projectid: r.Projectid,
Expand Down
9 changes: 4 additions & 5 deletions cmd/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,10 @@ func partitionResponseToCreate(r *models.V1PartitionResponse) *models.V1Partitio
Imageurl: r.Bootconfig.Imageurl,
Kernelurl: r.Bootconfig.Kernelurl,
},
Description: r.Description,
ID: r.ID,
Mgmtserviceaddress: r.Mgmtserviceaddress,
Name: r.Name,
Privatenetworkprefixlength: r.Privatenetworkprefixlength,
Description: r.Description,
ID: r.ID,
Mgmtserviceaddress: r.Mgmtserviceaddress,
Name: r.Name,
}
}

Expand Down
19 changes: 8 additions & 11 deletions cmd/partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ var (
Imageurl: "imageurl",
Kernelurl: "kernelurl",
},
Description: "partition 1",
ID: pointer.Pointer("1"),
Mgmtserviceaddress: "mgmt",
Name: "partition-1",
Privatenetworkprefixlength: 24,
Description: "partition 1",
ID: pointer.Pointer("1"),
Mgmtserviceaddress: "mgmt",
Name: "partition-1",
Labels: map[string]string{
"a": "b",
},
Expand All @@ -36,11 +35,10 @@ var (
Imageurl: "imageurl",
Kernelurl: "kernelurl",
},
Description: "partition 2",
ID: pointer.Pointer("2"),
Mgmtserviceaddress: "mgmt",
Name: "partition-2",
Privatenetworkprefixlength: 24,
Description: "partition 2",
ID: pointer.Pointer("2"),
Mgmtserviceaddress: "mgmt",
Name: "partition-2",
}
)

Expand Down Expand Up @@ -239,7 +237,6 @@ ID NAME DESCRIPTION LABELS
mocks: &client.MetalMockFns{
Partition: func(mock *mock.Mock) {
p := partition1
p.Privatenetworkprefixlength = 0
mock.On("CreatePartition", testcommon.MatchIgnoreContext(t, partition.NewCreatePartitionParams().WithBody(partitionResponseToCreate(p))), nil).Return(&partition.CreatePartitionCreated{
Payload: partition1,
}, nil)
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
19 changes: 11 additions & 8 deletions docs/metalctl_network_allocate.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ metalctl network allocate [flags]
### Options

```
-d, --description string description of the network to create. [optional]
--dmz use this private network as dmz. [optional]
-h, --help help for allocate
--labels strings labels for this network. [optional]
-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]
--shared shared allows usage of this private network from other networks
--addressfamily string addressfamily of the network to acquire [optional] (default "ipv4")
-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]
-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]
--shared shared allows usage of this private network from other networks
```

### Options inherited from parent commands
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: age|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: age|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
1 change: 1 addition & 0 deletions docs/metalctl_network_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ metalctl network list [flags]
### Options

```
--addressfamily string addressfamily to filter, either ipv4 or ipv6 [optional]
--destination-prefixes strings destination prefixes to filter, use it like: --destination-prefixes prefix1,prefix2.
-h, --help help for list
--id string ID to filter [optional]
Expand Down
Loading