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

Merged
merged 33 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8c1af87
IPv6 Support
majst01 Jul 4, 2024
131fdc6
Merge branch 'master' of https://github.com/metal-stack/metalctl into…
majst01 Jul 8, 2024
dfe9cef
Merge master
majst01 Jul 11, 2024
6d903e2
Dualstack Support
majst01 Jul 19, 2024
95fc117
Merge master
majst01 Aug 2, 2024
7763267
Merge master
majst01 Sep 5, 2024
c3450d2
Merge master
majst01 Oct 3, 2024
f0113de
Merge master
majst01 Nov 13, 2024
549cd31
Merge branch 'master' into dualstack-support
majst01 Nov 13, 2024
37b52ae
Merge branch 'master' of https://github.com/metal-stack/metalctl into…
majst01 Nov 13, 2024
460def1
Merge branch 'dualstack-support' of https://github.com/metal-stack/me…
majst01 Nov 13, 2024
054fe3e
Update deps
majst01 Dec 20, 2024
1414c31
Allow update DefaultChildPrefixLength
majst01 Jan 2, 2025
362cffc
Adoption
majst01 Jan 13, 2025
c5f353e
Adopt Usage->Consumption migration
majst01 Jan 16, 2025
0f26251
Server side filtering by addressfamily
majst01 Jan 18, 2025
3a34179
Adopt metal-go
majst01 Jan 23, 2025
7ac134e
Merge master
majst01 Jan 23, 2025
ab4b109
Adopt
majst01 Jan 24, 2025
1493ba2
Fix ip apply
majst01 Jan 24, 2025
6e0f7ff
Allow setting default child prefix length on network creation.
Gerrit91 Jan 29, 2025
c2acbe5
Merge branch 'master' into dualstack-support
Gerrit91 Feb 19, 2025
d43c7cc
Fix tests.
Gerrit91 Feb 19, 2025
044da3d
Pin metal-go
majst01 Feb 19, 2025
3696f24
Pin
majst01 Feb 19, 2025
923dc53
Update cmd/ip_test.go
majst01 Feb 19, 2025
3a5aee9
Update cmd/network.go
majst01 Feb 19, 2025
f92a385
Update cmd/network.go
majst01 Feb 19, 2025
58ee3e7
One less fixme
majst01 Feb 19, 2025
8b1e5ac
Update cmd/network.go
majst01 Feb 19, 2025
23dca20
last commit
majst01 Feb 19, 2025
8280f91
Merge branch 'dualstack-support' of https://github.com/metal-stack/me…
majst01 Feb 19, 2025
54fac6d
Review findings
majst01 Feb 19, 2025
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.20
FROM alpine:3.21
LABEL maintainer="metal-stack authors <[email protected]>"
COPY bin/metalctl-linux-amd64 /metalctl
ENTRYPOINT ["/metalctl"]
2 changes: 1 addition & 1 deletion Dockerfile.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.23
FROM golang:1.24
WORKDIR /work
COPY go.* .
RUN go mod download
Expand Down
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
}
27 changes: 21 additions & 6 deletions cmd/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,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 +64,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 @@ -105,6 +109,7 @@ func (c *ipCmd) List() ([]*models.V1IPResponse, error) {
Machineid: viper.GetString("machineid"),
Networkprefix: viper.GetString("prefix"),
Tags: viper.GetStringSlice("tags"),
Addressfamily: viper.GetString("addressfamily"),
}), nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -136,6 +141,8 @@ func (c *ipCmd) Create(rq *ipAllocateRequest) (*models.V1IPResponse, error) {
return resp.Payload, nil
}

// FIXME this is a workaround, if specificIP is set, AF must not be set.
rq.Addressfamily = nil
resp, err := c.client.IP().AllocateSpecificIP(ip.NewAllocateSpecificIPParams().WithIP(rq.SpecificIP).WithBody(rq.V1IPAllocateRequest), nil)
if err != nil {
var r *ip.AllocateSpecificIPConflict
Expand Down Expand Up @@ -169,6 +176,7 @@ func ipResponseToCreate(r *models.V1IPResponse) *ipAllocateRequest {
if r.Ipaddress != nil {
ip = *r.Ipaddress
}

return &ipAllocateRequest{
SpecificIP: ip,
V1IPAllocateRequest: &models.V1IPAllocateRequest{
Expand All @@ -193,15 +201,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, // TODO: this is not correct for specificip, but makes the matcher happy.
}
assertExhaustiveArgs(t, args, commonExcludedFileArgs()...)
return args
Expand Down
53 changes: 53 additions & 0 deletions cmd/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"
"fmt"
"strconv"

"slices"

Expand Down Expand Up @@ -46,6 +47,8 @@ func newNetworkCmd(c *config) *cobra.Command {
cmd.Flags().StringP("name", "n", "", "name of the network to create. [optional]")
cmd.Flags().StringP("partition", "p", "", "partition where this network should exist.")
cmd.Flags().StringP("project", "", "", "project of the network to create. [optional]")
cmd.Flags().Int64("default-ipv4-child-prefix-length", 0, "default child prefix length for ipv4 prefixes for private super networks.")
cmd.Flags().Int64("default-ipv6-child-prefix-length", 0, "default child prefix length for ipv6 prefixes for private super networks.")
cmd.Flags().StringSlice("prefixes", []string{}, "prefixes in this network.")
cmd.Flags().StringSlice("labels", []string{}, "add initial labels, must be in the form of key=value, use it like: --labels \"key1=value1,key2=value2\".")
cmd.Flags().StringSlice("destination-prefixes", []string{}, "destination prefixes in this network.")
Expand All @@ -70,8 +73,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 +110,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 +133,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 +163,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 @@ -179,6 +204,7 @@ 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 Expand Up @@ -235,6 +261,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 All @@ -256,6 +283,7 @@ func networkResponseToUpdate(r *models.V1NetworkResponse) *models.V1NetworkUpdat
Prefixes: r.Prefixes,
Shared: r.Shared,
AdditionalAnnouncableCIDRs: r.AdditionalAnnouncableCIDRs,
Defaultchildprefixlength: r.Defaultchildprefixlength,
}
}

Expand All @@ -265,6 +293,18 @@ func (c *networkCmd) createRequestFromCLI() (*models.V1NetworkCreateRequest, err
return nil, err
}

var defaultChildPrefixLengths map[string]int64
if viper.GetBool("privatesuper") {
defaultChildPrefixLengths = map[string]int64{}

if length := viper.GetInt64("default-ipv4-child-prefix-length"); length > 0 {
defaultChildPrefixLengths[models.V1IPAllocateRequestAddressfamilyIPV4] = length
}
if length := viper.GetInt64("default-ipv6-child-prefix-length"); length > 0 {
defaultChildPrefixLengths[models.V1IPAllocateRequestAddressfamilyIPV6] = length
}
}

return &models.V1NetworkCreateRequest{
ID: pointer.Pointer(viper.GetString("id")),
Description: viper.GetString("description"),
Expand All @@ -280,6 +320,7 @@ func (c *networkCmd) createRequestFromCLI() (*models.V1NetworkCreateRequest, err
Vrfshared: viper.GetBool("vrfshared"),
Labels: lbs,
AdditionalAnnouncableCIDRs: viper.GetStringSlice("additional-announcable-cidrs"),
Defaultchildprefixlength: defaultChildPrefixLengths,
}, nil
}

Expand Down Expand Up @@ -365,6 +406,17 @@ func (c *networkCmd) updateRequestFromCLI(args []string) (*models.V1NetworkUpdat
if viper.IsSet("additional-announcable-cidrs") {
additionalCidrs = viper.GetStringSlice("additional-announcable-cidrs")
}
defaultchildprefixlength := resp.Defaultchildprefixlength
if viper.IsSet("default-child-prefixlength") {
defaultchildprefixlengthMap := viper.GetStringMapString("default-child-prefixlength")
for af, length := range defaultchildprefixlengthMap {
l, err := strconv.Atoi(length)
if err != nil {
return nil, err
}
defaultchildprefixlength[af] = int64(l)
}
}
var (
ur = &models.V1NetworkUpdateRequest{
Description: viper.GetString("description"),
Expand All @@ -375,6 +427,7 @@ func (c *networkCmd) updateRequestFromCLI(args []string) (*models.V1NetworkUpdat
Prefixes: nil,
Shared: shared,
AdditionalAnnouncableCIDRs: additionalCidrs,
Defaultchildprefixlength: defaultchildprefixlength,
}
addPrefixes = sets.New(viper.GetStringSlice("add-prefixes")...)
removePrefixes = sets.New(viper.GetStringSlice("remove-prefixes")...)
Expand Down
43 changes: 28 additions & 15 deletions cmd/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,21 @@ var (
Projectid: "",
Shared: false,
Underlay: pointer.Pointer(true),
Usage: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(100)),
AvailablePrefixes: pointer.Pointer(int64(200)),
UsedIps: pointer.Pointer(int64(300)),
UsedPrefixes: pointer.Pointer(int64(400)),
Consumption: &models.V1NetworkConsumption{
IPV4: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(100)),
AvailablePrefixes: pointer.Pointer(int64(200)),
UsedIps: pointer.Pointer(int64(300)),
UsedPrefixes: pointer.Pointer(int64(400)),
},
},
Vrf: 50,
Vrfshared: true,
AdditionalAnnouncableCIDRs: []string{"10.240.0.0/12"},
Defaultchildprefixlength: map[string]int64{
"IPv4": 22,
"IPv6": 96,
},
}
network1child = &models.V1NetworkResponse{
Description: "child 1",
Expand All @@ -57,11 +63,13 @@ var (
Projectid: "project-1",
Shared: false,
Underlay: pointer.Pointer(false),
Usage: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(100)),
AvailablePrefixes: pointer.Pointer(int64(200)),
UsedIps: pointer.Pointer(int64(300)),
UsedPrefixes: pointer.Pointer(int64(400)),
Consumption: &models.V1NetworkConsumption{
IPV4: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(100)),
AvailablePrefixes: pointer.Pointer(int64(200)),
UsedIps: pointer.Pointer(int64(300)),
UsedPrefixes: pointer.Pointer(int64(400)),
},
},
Vrf: 50,
Vrfshared: true,
Expand All @@ -81,11 +89,13 @@ var (
Projectid: "project-1",
Shared: false,
Underlay: pointer.Pointer(false),
Usage: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(400)),
AvailablePrefixes: pointer.Pointer(int64(300)),
UsedIps: pointer.Pointer(int64(200)),
UsedPrefixes: pointer.Pointer(int64(100)),
Consumption: &models.V1NetworkConsumption{
IPV4: &models.V1NetworkUsage{
AvailableIps: pointer.Pointer(int64(400)),
AvailablePrefixes: pointer.Pointer(int64(300)),
UsedIps: pointer.Pointer(int64(200)),
UsedPrefixes: pointer.Pointer(int64(100)),
},
},
Vrf: 60,
Vrfshared: true,
Expand Down Expand Up @@ -301,6 +311,8 @@ nw1 network-1
"--vrf", strconv.FormatInt(want.Vrf, 10),
"--vrfshared", strconv.FormatBool(want.Vrfshared),
"--additional-announcable-cidrs", "10.240.0.0/12",
"--default-ipv4-child-prefix-length", "22",
"--default-ipv6-child-prefix-length", "96",
}
assertExhaustiveArgs(t, args, commonExcludedFileArgs()...)
return args
Expand Down Expand Up @@ -350,6 +362,7 @@ nw1 network-1
Labels: network1.Labels,
Shared: network1.Shared,
AdditionalAnnouncableCIDRs: network1.AdditionalAnnouncableCIDRs,
Defaultchildprefixlength: network1.Defaultchildprefixlength,
}).WithForce(pointer.Pointer(false))), nil).Return(&network.UpdateNetworkOK{
Payload: network1,
}, nil)
Expand Down
13 changes: 6 additions & 7 deletions cmd/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,12 @@ 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,
DNSServers: r.DNSServers,
NtpServers: r.NtpServers,
Description: r.Description,
ID: r.ID,
Mgmtserviceaddress: r.Mgmtserviceaddress,
Name: r.Name,
DNSServers: r.DNSServers,
NtpServers: r.NtpServers,
}
}

Expand Down
Loading
Loading