Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
Browse files Browse the repository at this point in the history
…o dualstack-support
  • Loading branch information
majst01 committed Aug 9, 2024
2 parents c519d3b + 7a5f643 commit a1575ef
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 100 deletions.
3 changes: 3 additions & 0 deletions cmd/metal-api/internal/datastore/network_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ func (_ *networkTestable) defaultBody(n *metal.Network) *metal.Network {
if n.DestinationPrefixes == nil {
n.DestinationPrefixes = metal.Prefixes{}
}
if n.AdditionalAnnouncableCIDRs == nil {
n.AdditionalAnnouncableCIDRs = []string{}
}
return n
}

Expand Down
27 changes: 14 additions & 13 deletions cmd/metal-api/internal/metal/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,20 @@ func (p *Prefix) equals(other *Prefix) bool {
// TODO specify rethinkdb restrictions.
type Network struct {
Base
Prefixes Prefixes `rethinkdb:"prefixes" json:"prefixes"`
DestinationPrefixes Prefixes `rethinkdb:"destinationprefixes" json:"destinationprefixes"`
DefaultChildPrefixLength ChildPrefixLength `rethinkdb:"defaultchildprefixlength" json:"childprefixlength" description:"if privatesuper, this defines the bitlen of child prefixes per addressfamily if not nil"`
PartitionID string `rethinkdb:"partitionid" json:"partitionid"`
ProjectID string `rethinkdb:"projectid" json:"projectid"`
ParentNetworkID string `rethinkdb:"parentnetworkid" json:"parentnetworkid"`
Vrf uint `rethinkdb:"vrf" json:"vrf"`
PrivateSuper bool `rethinkdb:"privatesuper" json:"privatesuper"`
Nat bool `rethinkdb:"nat" json:"nat"`
Underlay bool `rethinkdb:"underlay" json:"underlay"`
Shared bool `rethinkdb:"shared" json:"shared"`
Labels map[string]string `rethinkdb:"labels" json:"labels"`
AddressFamilies AddressFamilies `rethinkdb:"addressfamily" json:"addressfamily"`
Prefixes Prefixes `rethinkdb:"prefixes" json:"prefixes"`
DestinationPrefixes Prefixes `rethinkdb:"destinationprefixes" json:"destinationprefixes"`
DefaultChildPrefixLength ChildPrefixLength `rethinkdb:"defaultchildprefixlength" json:"childprefixlength" description:"if privatesuper, this defines the bitlen of child prefixes per addressfamily if not nil"`
PartitionID string `rethinkdb:"partitionid" json:"partitionid"`
ProjectID string `rethinkdb:"projectid" json:"projectid"`
ParentNetworkID string `rethinkdb:"parentnetworkid" json:"parentnetworkid"`
Vrf uint `rethinkdb:"vrf" json:"vrf"`
PrivateSuper bool `rethinkdb:"privatesuper" json:"privatesuper"`
Nat bool `rethinkdb:"nat" json:"nat"`
Underlay bool `rethinkdb:"underlay" json:"underlay"`
Shared bool `rethinkdb:"shared" json:"shared"`
Labels map[string]string `rethinkdb:"labels" json:"labels"`
AddressFamilies AddressFamilies `rethinkdb:"addressfamily" json:"addressfamily"`
AdditionalAnnouncableCIDRs []string `rethinkdb:"additionalannouncablecidrs" json:"additionalannouncablecidrs" description:"list of cidrs which are added to the route maps per tenant private network, these are typically pod- and service cidrs, can only be set in a supernetwork"`
}

type ChildPrefixLength map[AddressFamily]uint8
Expand Down
53 changes: 42 additions & 11 deletions cmd/metal-api/internal/service/network-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,12 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
return
}

additionalRouteMapCIDRs, err := validateAdditionalRouteMapCIDRs(requestPayload.AdditionalAnnouncableCIDRs, privateSuper)
if err != nil {
r.sendError(request, response, httperrors.BadRequest(err))
return
}

if vrf != 0 {
err = acquireVRF(r.ds, vrf)
if err != nil {
Expand All @@ -389,17 +395,18 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
Name: name,
Description: description,
},
Prefixes: prefixes,
DestinationPrefixes: destPrefixes,
DefaultChildPrefixLength: childPrefixLength,
PartitionID: partitionID,
ProjectID: projectID,
Nat: nat,
PrivateSuper: privateSuper,
Underlay: underlay,
Vrf: vrf,
Labels: labels,
AddressFamilies: addressFamilies,
Prefixes: prefixes,
DestinationPrefixes: destPrefixes,
DefaultChildPrefixLength: childPrefixLength,
PartitionID: partitionID,
ProjectID: projectID,
Nat: nat,
PrivateSuper: privateSuper,
Underlay: underlay,
Vrf: vrf,
Labels: labels,
AddressFamilies: addressFamilies,
AdditionalAnnouncableCIDRs: additionalRouteMapCIDRs,
}

ctx := request.Request.Context()
Expand All @@ -426,6 +433,23 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
r.send(request, response, http.StatusCreated, v1.NewNetworkResponse(nw, usage))
}

func validateAdditionalRouteMapCIDRs(additionalCidrs []string, privateSuper bool) ([]string, error) {
var result []string
if len(additionalCidrs) > 0 {
if !privateSuper {
return nil, errors.New("additionalroutemapcidrs can only be set in a private super network")
}
for _, cidr := range additionalCidrs {
_, err := netip.ParsePrefix(cidr)
if err != nil {
return nil, fmt.Errorf("given cidr:%q in additionalroutemapcidrs is malformed:%s", cidr, err)

Check failure on line 445 in cmd/metal-api/internal/service/network-service.go

View workflow job for this annotation

GitHub Actions / Docker Build

non-wrapping format verb for fmt.Errorf. Use `%w` to format errors (errorlint)
}
result = append(result, cidr)
}
}
return result, nil
}

func validatePrefixesAndAddressFamilies(prefixes, destinationPrefixes []string, defaultChildPrefixLength metal.ChildPrefixLength, privateSuper bool) (metal.Prefixes, metal.Prefixes, metal.AddressFamilies, error) {

pfxs, addressFamilies, err := validatePrefixes(prefixes)
Expand Down Expand Up @@ -822,6 +846,13 @@ func (r *networkResource) updateNetwork(request *restful.Request, response *rest
}
}

additionalRouteMapCIDRs, err := validateAdditionalRouteMapCIDRs(requestPayload.AdditionalAnnouncableCIDRs, oldNetwork.PrivateSuper)
if err != nil {
r.sendError(request, response, defaultError(err))
return
}
newNetwork.AdditionalAnnouncableCIDRs = additionalRouteMapCIDRs

err = r.ds.UpdateNetwork(oldNetwork, &newNetwork)
if err != nil {
r.sendError(request, response, defaultError(err))
Expand Down
58 changes: 36 additions & 22 deletions cmd/metal-api/internal/service/switch-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (r *switchResource) findSwitch(request *restful.Request, response *restful.
return
}

resp, err := makeSwitchResponse(s, r.ds)
resp, err := r.makeSwitchResponse(s)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand All @@ -159,7 +159,7 @@ func (r *switchResource) listSwitches(request *restful.Request, response *restfu
return
}

resp, err := makeSwitchResponseList(ss, r.ds)
resp, err := r.makeSwitchResponseList(ss, r.ds)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand All @@ -183,7 +183,7 @@ func (r *switchResource) findSwitches(request *restful.Request, response *restfu
return
}

resp, err := makeSwitchResponseList(ss, r.ds)
resp, err := r.makeSwitchResponseList(ss, r.ds)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand Down Expand Up @@ -222,7 +222,7 @@ func (r *switchResource) deleteSwitch(request *restful.Request, response *restfu
return
}

resp, err := makeSwitchResponse(s, r.ds)
resp, err := r.makeSwitchResponse(s)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand Down Expand Up @@ -387,7 +387,7 @@ func (r *switchResource) toggleSwitchPort(request *restful.Request, response *re
}
}

resp, err := makeSwitchResponse(&newSwitch, r.ds)
resp, err := r.makeSwitchResponse(&newSwitch)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand Down Expand Up @@ -436,7 +436,7 @@ func (r *switchResource) updateSwitch(request *restful.Request, response *restfu
return
}

resp, err := makeSwitchResponse(&newSwitch, r.ds)
resp, err := r.makeSwitchResponse(&newSwitch)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand Down Expand Up @@ -552,7 +552,7 @@ func (r *switchResource) registerSwitch(request *restful.Request, response *rest

}

resp, err := makeSwitchResponse(s, r.ds)
resp, err := r.makeSwitchResponse(s)
if err != nil {
r.sendError(request, response, defaultError(err))
return
Expand Down Expand Up @@ -771,22 +771,22 @@ func updateSwitchNics(oldNics, newNics map[string]*metal.Nic, currentConnections
return finalNics, nil
}

func makeSwitchResponse(s *metal.Switch, ds *datastore.RethinkStore) (*v1.SwitchResponse, error) {
p, ips, machines, ss, err := findSwitchReferencedEntities(s, ds)
func (r *switchResource) makeSwitchResponse(s *metal.Switch) (*v1.SwitchResponse, error) {
p, ips, machines, ss, err := findSwitchReferencedEntities(s, r.ds)
if err != nil {
return nil, err
}

nics, err := makeSwitchNics(s, ips, machines)
nics, err := r.makeSwitchNics(s, ips, machines)
if err != nil {
return nil, err
}
cons := makeSwitchCons(s)
cons := r.makeSwitchCons(s)

return v1.NewSwitchResponse(s, ss, p, nics, cons), nil
}

func makeBGPFilterFirewall(m metal.Machine) (v1.BGPFilter, error) {
func (r *switchResource) makeBGPFilterFirewall(m metal.Machine) (v1.BGPFilter, error) {
vnis := []string{}
cidrs := []string{}

Expand All @@ -808,7 +808,7 @@ func makeBGPFilterFirewall(m metal.Machine) (v1.BGPFilter, error) {
return v1.NewBGPFilter(vnis, cidrs), nil
}

func makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, error) {
func (r *switchResource) makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, error) {
vnis := []string{}
cidrs := []string{}

Expand All @@ -825,6 +825,20 @@ func makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, erro
// Allow all prefixes of the private network
if private != nil {
cidrs = append(cidrs, private.Prefixes...)

privateNetwork, err := r.ds.FindNetworkByID(private.NetworkID)
if err != nil {
return v1.BGPFilter{}, err
}
parentNetwork, err := r.ds.FindNetworkByID(privateNetwork.ID)
if err != nil {
return v1.BGPFilter{}, err
}
// Only for private networks, additionalRouteMapCidrs are applied.
// they contain usually the pod- and service- cidrs in a kubernetes cluster
if len(parentNetwork.AdditionalAnnouncableCIDRs) > 0 {
cidrs = append(cidrs, parentNetwork.AdditionalAnnouncableCIDRs...)
}
}
for _, i := range ips[m.Allocation.Project] {
// No need to add /32 addresses of the primary network to the whitelist.
Expand Down Expand Up @@ -854,7 +868,7 @@ func ipWithMask(ip string) (string, error) {
return fmt.Sprintf("%s/%d", ip, parsed.BitLen()), nil
}

func makeBGPFilter(m metal.Machine, vrf string, ips metal.IPsMap) (v1.BGPFilter, error) {
func (r *switchResource) makeBGPFilter(m metal.Machine, vrf string, ips metal.IPsMap) (v1.BGPFilter, error) {
var (
filter v1.BGPFilter
err error
Expand All @@ -864,16 +878,16 @@ func makeBGPFilter(m metal.Machine, vrf string, ips metal.IPsMap) (v1.BGPFilter,
// vrf "default" means: the firewall was successfully allocated and the switch port configured
// otherwise the port is still not configured yet (pxe-setup) and a BGPFilter would break the install routine
if vrf == "default" {
filter, err = makeBGPFilterFirewall(m)
filter, err = r.makeBGPFilterFirewall(m)
}
} else {
filter, err = makeBGPFilterMachine(m, ips)
filter, err = r.makeBGPFilterMachine(m, ips)
}

return filter, err
}

func makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machines metal.Machines) (v1.SwitchNics, error) {
func (r *switchResource) makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machines metal.Machines) (v1.SwitchNics, error) {
machinesByID := map[string]*metal.Machine{}
for i, m := range machines {
machinesByID[m.ID] = &machines[i]
Expand All @@ -894,7 +908,7 @@ func makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machines metal.Machines)
m := machinesBySwp[n.Name]
var filter *v1.BGPFilter
if m != nil && m.Allocation != nil {
f, err := makeBGPFilter(*m, n.Vrf, ips)
f, err := r.makeBGPFilter(*m, n.Vrf, ips)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -925,7 +939,7 @@ func makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machines metal.Machines)
return nics, nil
}

func makeSwitchCons(s *metal.Switch) []v1.SwitchConnection {
func (r *switchResource) makeSwitchCons(s *metal.Switch) []v1.SwitchConnection {
cons := []v1.SwitchConnection{}

nicMap := s.Nics.ByName()
Expand Down Expand Up @@ -996,7 +1010,7 @@ func findSwitchReferencedEntities(s *metal.Switch, ds *datastore.RethinkStore) (
return p, ips.ByProjectID(), m, ss, nil
}

func makeSwitchResponseList(ss metal.Switches, ds *datastore.RethinkStore) ([]*v1.SwitchResponse, error) {
func (r *switchResource) makeSwitchResponseList(ss metal.Switches, ds *datastore.RethinkStore) ([]*v1.SwitchResponse, error) {
pMap, ips, err := getSwitchReferencedEntityMaps(ds)
if err != nil {
return nil, err
Expand All @@ -1016,11 +1030,11 @@ func makeSwitchResponseList(ss metal.Switches, ds *datastore.RethinkStore) ([]*v
p = &partitionEntity
}

nics, err := makeSwitchNics(&sw, ips, m)
nics, err := r.makeSwitchNics(&sw, ips, m)
if err != nil {
return nil, err
}
cons := makeSwitchCons(&sw)
cons := r.makeSwitchCons(&sw)
ss, err := ds.GetSwitchStatus(sw.ID)
if err != nil && !metal.IsNotFound(err) {
return nil, err
Expand Down
18 changes: 15 additions & 3 deletions cmd/metal-api/internal/service/switch-service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ func TestMakeBGPFilterFirewall(t *testing.T) {
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
got, _ := makeBGPFilterFirewall(tt.args.machine)
r := switchResource{}
got, _ := r.makeBGPFilterFirewall(tt.args.machine)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeBGPFilterFirewall() = %v, want %v", got, tt.want)
}
Expand All @@ -412,6 +413,9 @@ func TestMakeBGPFilterFirewall(t *testing.T) {
}

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

type args struct {
machine metal.Machine
ipsMap metal.IPsMap
Expand Down Expand Up @@ -493,10 +497,17 @@ func TestMakeBGPFilterMachine(t *testing.T) {
want: v1.NewBGPFilter([]string{}, []string{"212.89.42.1/32"}),
},
}

for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
got, _ := makeBGPFilterMachine(tt.args.machine, tt.args.ipsMap)
// FIXME return super network with additionalroutemapcidrs set
mock.On(r.DB("mockdb").Table("network").Get(r.MockAnything()).Replace(r.MockAnything())).Return(testdata.EmptyResult, nil)
mock.On(r.DB("mockdb").Table("network").Get(r.MockAnything()).Replace(r.MockAnything())).Return(testdata.EmptyResult, nil)

r := switchResource{webResource: webResource{ds: ds}}

got, _ := r.makeBGPFilterMachine(tt.args.machine, tt.args.ipsMap)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeBGPFilterMachine() = %v, want %v", got, tt.want)
}
Expand Down Expand Up @@ -603,7 +614,8 @@ func TestMakeSwitchNics(t *testing.T) {
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
got, _ := makeSwitchNics(tt.args.s, tt.args.ips, tt.args.machines)
r := switchResource{}
got, _ := r.makeSwitchNics(tt.args.s, tt.args.ips, tt.args.machines)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeSwitchNics() = %v, want %v", got, tt.want)
}
Expand Down
Loading

0 comments on commit a1575ef

Please sign in to comment.