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

use go-ipam with ipv6 support #152

Draft
wants to merge 43 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
dbcab7c
use go-ipam with ipv6 support
majst01 Jan 1, 2021
baee168
disable actually unused var
majst01 Jan 1, 2021
adbf0a4
update go-ipam
majst01 Jan 1, 2021
c7a1b4b
Adopt to latest available prefix calculation in go-ipam
majst01 Jan 6, 2021
f91ebb0
Some simple ipv6 tests
majst01 Jan 6, 2021
cd215e3
Update go-ipam
majst01 Jan 12, 2021
fe5a998
Adopt spec
majst01 Jan 12, 2021
0d61326
update to latest go-ipam ipv6 branch
majst01 Jan 13, 2021
a4e5ac0
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jan 14, 2021
1ba03f0
fixate to tagged go-ipam
majst01 Jan 14, 2021
d00a27a
calculate network usage again
majst01 Jan 15, 2021
7bf550f
Merge master
majst01 Jan 21, 2021
7c4c91f
make child prefix acquire work for ipv6
majst01 Jan 21, 2021
19c163e
make child prefix acquire work for ipv6
majst01 Jan 21, 2021
16e8a11
debug usage
majst01 Jan 21, 2021
f4dd5cb
debug usage
majst01 Jan 21, 2021
68d3bdc
Debug usage
majst01 Jan 21, 2021
5cf6fd5
Fix prefix usage
majst01 Jan 22, 2021
6fe14d8
Fix prefix usage
majst01 Jan 22, 2021
c6e4cae
Forgot to add one struct member
majst01 Jan 22, 2021
ab72e96
Keep rest-api compatible with existing metalctl versions
majst01 Jan 27, 2021
1945032
Move childprefixlength to the privatesuper network
majst01 Jan 27, 2021
db5a43c
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jan 27, 2021
ab0a080
migrate partition.privatenetworklength to network.childprefixlength
majst01 Jan 27, 2021
fd5da95
all prefixes must be of the same addressfamily and childprefixlenth m…
majst01 Jan 27, 2021
92d11e6
Set childprefixlength
majst01 Jan 27, 2021
a51faad
updates
majst01 Jan 27, 2021
50b0bb7
Better migration
majst01 Jan 27, 2021
5a1bcbe
Allow two supernetworks with distinct addressfamilies per partition, …
majst01 Jan 28, 2021
5158c5c
allow child prefix length to be specified during network allocate
majst01 Jan 28, 2021
4a204d5
childprefix is optional and must be greater than prefix length
majst01 Jan 28, 2021
2fed155
cannot cast strings to a addressfamily
majst01 Jan 28, 2021
56c6ddf
Debug
majst01 Jan 28, 2021
078ea3b
ensure supernetwork has childprefixlength specified
majst01 Jan 28, 2021
bd93719
typo
majst01 Jan 28, 2021
25271f7
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jan 29, 2021
5d4d3ba
update go-ipam
majst01 Feb 1, 2021
f7d9121
Use go-ipam v1.8.1
majst01 Feb 1, 2021
40e8997
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Feb 4, 2021
dfd1ffb
More tests
majst01 Feb 5, 2021
6e69d4f
Uuups
majst01 Feb 5, 2021
5bc7f3b
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Feb 8, 2021
c230107
Updates
majst01 Feb 8, 2021
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package migrations

import (
r "gopkg.in/rethinkdb/rethinkdb-go.v6"

"github.com/metal-stack/metal-api/cmd/metal-api/internal/datastore"
)

func init() {
type tmpPartition struct {
PrivateNetworkPrefixLength uint8 `rethinkdb:"privatenetworkprefixlength"`
}
datastore.MustRegisterMigration(datastore.Migration{
Name: "migrate partition.childprefixlength to tenant super network",
Version: 3,
Up: func(db *r.Term, session r.QueryExecutor, rs *datastore.RethinkStore) error {
nws, err := rs.ListNetworks()
if err != nil {
return err
}

for _, old := range nws {
if !old.PrivateSuper {
continue
}

cursor, err := db.Table("partition").Get(old.PartitionID).Run(session)
if err != nil {
return err
}
var partition tmpPartition
err = cursor.One(&partition)
if err != nil {
return err
}

new := old
new.ChildPrefixLength = &partition.PrivateNetworkPrefixLength
err = rs.UpdateNetwork(&old, &new)
if err != nil {
return err
}
err = cursor.Close()
if err != nil {
return err
}
}

_, err = db.Table("partition").Replace(r.Row.Without("privatenetworkprefixlength")).RunWrite(session)
return err
},
})
}
12 changes: 6 additions & 6 deletions cmd/metal-api/internal/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func New(ip ipam.Ipamer) *Ipam {
}

// AllocateChildPrefix creates a child prefix from a parent prefix in the IPAM.
func (i *Ipam) AllocateChildPrefix(parentPrefix metal.Prefix, childLength int) (*metal.Prefix, error) {
func (i *Ipam) AllocateChildPrefix(parentPrefix metal.Prefix, childLength uint8) (*metal.Prefix, error) {
ipamParentPrefix := i.ip.PrefixFrom(parentPrefix.String())

if ipamParentPrefix == nil {
Expand Down Expand Up @@ -131,12 +131,12 @@ func (i *Ipam) PrefixUsage(cidr string) (*metal.NetworkUsage, error) {
return nil, fmt.Errorf("prefix for cidr:%s not found", cidr)
}
usage := prefix.Usage()

return &metal.NetworkUsage{
AvailableIPs: usage.AvailableIPs,
UsedIPs: usage.AcquiredIPs,
AvailablePrefixes: usage.AvailablePrefixes,
UsedPrefixes: usage.AcquiredPrefixes,
AvailableIPs: usage.AvailableIPs,
UsedIPs: usage.AcquiredIPs,
AvailablePrefixes: usage.AvailableSmallestPrefixes,
AvailablePrefixList: usage.AvailablePrefixes,
UsedPrefixes: usage.AcquiredPrefixes,
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/metal-api/internal/ipam/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type IPAMer interface {
AllocateIP(prefix metal.Prefix) (string, error)
AllocateSpecificIP(prefix metal.Prefix, specificIP string) (string, error)
ReleaseIP(ip metal.IP) error
AllocateChildPrefix(parentPrefix metal.Prefix, childLength int) (*metal.Prefix, error)
AllocateChildPrefix(parentPrefix metal.Prefix, childLength uint8) (*metal.Prefix, error)
ReleaseChildPrefix(childPrefix metal.Prefix) error
CreatePrefix(prefix metal.Prefix) error
DeletePrefix(prefix metal.Prefix) error
Expand Down
26 changes: 14 additions & 12 deletions cmd/metal-api/internal/metal/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package metal
import (
"fmt"
"net"
"strings"

"inet.af/netaddr"
)

// A MacAddress is the type for mac adresses. When using a
Expand Down Expand Up @@ -32,15 +33,13 @@ type Prefixes []Prefix

// NewPrefixFromCIDR returns a new prefix from a given cidr.
func NewPrefixFromCIDR(cidr string) (*Prefix, error) {
parts := strings.Split(cidr, "/")
if len(parts) != 2 {
return nil, fmt.Errorf("cannot split cidr into pieces: %v", cidr)
ipprefix, err := netaddr.ParseIPPrefix(cidr)
if err != nil {
return nil, err
}
ip := strings.TrimSpace(parts[0])
length := strings.TrimSpace(parts[1])
return &Prefix{
IP: ip,
Length: length,
IP: ipprefix.IP.String(),
Length: fmt.Sprintf("%d", ipprefix.Bits),
}, nil
}

Expand Down Expand Up @@ -73,6 +72,7 @@ type Network struct {
ParentNetworkID string `rethinkdb:"parentnetworkid" json:"parentnetworkid"`
Vrf uint `rethinkdb:"vrf" json:"vrf"`
PrivateSuper bool `rethinkdb:"privatesuper" json:"privatesuper"`
ChildPrefixLength *uint8 `rethinkdb:"childprefixlength" json:"childprefixlength" description:"if privatesuper, this defines the bitlen of child prefixes if not nil"`
Nat bool `rethinkdb:"nat" json:"nat"`
Underlay bool `rethinkdb:"underlay" json:"underlay"`
Shared bool `rethinkdb:"shared" json:"shared"`
Expand All @@ -87,10 +87,11 @@ type NetworkMap map[string]Network

// NetworkUsage contains usage information of a network
type NetworkUsage struct {
AvailableIPs uint64 `json:"available_ips" description:"the total available IPs" readonly:"true"`
UsedIPs uint64 `json:"used_ips" description:"the total used IPs" readonly:"true"`
AvailablePrefixes uint64 `json:"available_prefixes" description:"the total available Prefixes" readonly:"true"`
UsedPrefixes uint64 `json:"used_prefixes" description:"the total used Prefixes" readonly:"true"`
AvailableIPs uint64 `json:"available_ips" description:"the total available IPs" readonly:"true"`
UsedIPs uint64 `json:"used_ips" description:"the total used IPs" readonly:"true"`
AvailablePrefixes uint64 `json:"available_prefixes" description:"the total available 2 bit Prefixes" readonly:"true"`
AvailablePrefixList []string `json:"available_prefix_list" description:"a list of possible child prefixes"`
UsedPrefixes uint64 `json:"used_prefixes" description:"the total used Prefixes" readonly:"true"`
}

// ByID creates an indexed map of partitions whre the id is the index.
Expand Down Expand Up @@ -147,6 +148,7 @@ func (n *Network) SubstractPrefixes(prefixes ...Prefix) []Prefix {
return result
}

// NicMap returns the nic for a given macaddress
type NicMap map[MacAddress]*Nic

// ByMac creates a indexed map from a nic list.
Expand Down
5 changes: 2 additions & 3 deletions cmd/metal-api/internal/metal/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package metal
// A Partition represents a location.
type Partition struct {
Base
BootConfiguration BootConfiguration `rethinkdb:"bootconfig" json:"bootconfig"`
MgmtServiceAddress string `rethinkdb:"mgmtserviceaddr" json:"mgmtserviceaddr"`
PrivateNetworkPrefixLength int `rethinkdb:"privatenetworkprefixlength" json:"privatenetworkprefixlength"`
BootConfiguration BootConfiguration `rethinkdb:"bootconfig" json:"bootconfig"`
MgmtServiceAddress string `rethinkdb:"mgmtserviceaddr" json:"mgmtserviceaddr"`
}

// BootConfiguration defines the metal-hammer initrd, kernel and commandline
Expand Down
31 changes: 30 additions & 1 deletion cmd/metal-api/internal/service/ip-service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ func TestGetIPs(t *testing.T) {
err = json.NewDecoder(resp.Body).Decode(&result)

require.Nil(t, err)
require.Len(t, result, 3)
require.Len(t, result, 4)
require.Equal(t, testdata.IP1.IPAddress, result[0].IPAddress)
require.Equal(t, testdata.IP1.Name, *result[0].Name)
require.Equal(t, testdata.IP2.IPAddress, result[1].IPAddress)
require.Equal(t, testdata.IP2.Name, *result[1].Name)
require.Equal(t, testdata.IP3.IPAddress, result[2].IPAddress)
require.Equal(t, testdata.IP3.Name, *result[2].Name)
require.Equal(t, testdata.IP4.IPAddress, result[3].IPAddress)
require.Equal(t, testdata.IP4.Name, *result[3].Name)
}

func TestGetIP(t *testing.T) {
Expand All @@ -80,6 +82,28 @@ func TestGetIP(t *testing.T) {
require.Equal(t, testdata.IP1.Name, *result.Name)
}

func TestGetIPv6(t *testing.T) {
ds, mock := datastore.InitMockDB()
testdata.InitMockDBData(mock)

ipservice, err := NewIP(ds, bus.DirectEndpoints(), ipam.New(goipam.New()), nil)
require.NoError(t, err)
container := restful.NewContainer().Add(ipservice)
req := httptest.NewRequest("GET", "/v1/ip/2001:0db8:85a3::1", nil)
container = injectViewer(container, req)
w := httptest.NewRecorder()
container.ServeHTTP(w, req)

resp := w.Result()
require.Equal(t, http.StatusOK, resp.StatusCode, w.Body.String())
var result v1.IPResponse
err = json.NewDecoder(resp.Body).Decode(&result)

require.Nil(t, err)
require.Equal(t, testdata.IP4.IPAddress, result.IPAddress)
require.Equal(t, testdata.IP4.Name, *result.Name)
}

func TestGetIPNotFound(t *testing.T) {
ds, mock := datastore.InitMockDB()
testdata.InitMockDBData(mock)
Expand Down Expand Up @@ -127,6 +151,11 @@ func TestDeleteIP(t *testing.T) {
ip: testdata.IP3.IPAddress,
wantedStatus: http.StatusUnprocessableEntity,
},
{
name: "free a ipv6 ip should work",
ip: testdata.IP4.IPAddress,
wantedStatus: http.StatusUnprocessableEntity,
},
{
name: "free an cluster-ip should fail",
ip: testdata.IP2.IPAddress,
Expand Down
Loading