Skip to content

Commit

Permalink
Refactor IPPool selection code
Browse files Browse the repository at this point in the history
  • Loading branch information
haijianyang committed Mar 29, 2024
1 parent d5d7b1d commit 302431d
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 29 deletions.
10 changes: 10 additions & 0 deletions controllers/elfmachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,16 @@ func (r *ElfMachineReconciler) reconcileDeviceIPAddress(ctx *context.MachineCont
return ctrl.Result{}, nil
}

// getIPPool returns the specified IPPool.
//
// getIPPool selects IPPool according to the following priorities:
// (1) Without ip-pool-name
// 1. select IPPool with `is-default`` label from elfMachine.Namespace
// 2. select IPPool with `is-default` label from default namespace
// (2) With ip-pool-name(from AddressesFromPools or ElfMachineTemplate)
// 1. select IPPool using the specified ip-pool-name and ip-pool-namespace
// 2. select the IPPool named ip-pool-name in the default namespace

func (r *ElfMachineReconciler) getIPPool(ctx *context.MachineContext, device capev1.NetworkDeviceSpec) (ipam.IPPool, error) {
poolMatchLabels := make(map[string]string)
// Prefer IPPool of device. Only Metal3 IPPool is supported now.
Expand Down
2 changes: 2 additions & 0 deletions controllers/elfmachine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,11 @@ var _ = Describe("ElfMachineReconciler", func() {

It("should wait for IP when IPClaim without IP", func() {
ctrlutil.AddFinalizer(elfMachine, MachineStaticIPFinalizer)
metal3IPPool.Namespace = ipam.DefaultIPPoolNamespace
metal3IPPool.Labels = map[string]string{
ipam.ClusterIPPoolGroupKey: "ip-pool-group",
ipam.ClusterNetworkNameKey: "ip-pool-vm-network",
ipam.DefaultIPPoolKey: "true",
}
elfMachineTemplate.Labels = metal3IPPool.Labels
metal3IPClaim, metal3IPAddress = fake.NewMetal3IPObjects(metal3IPPool, ipamutil.GetFormattedClaimName(elfMachine.Namespace, elfMachine.Name, 0))
Expand Down
2 changes: 1 addition & 1 deletion pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ const (

// Default IPPool.
const (
DefaultIPPoolNamespace = "cape-system"
DefaultIPPoolNamespace = "default"
DefaultIPPoolKey = "ippool.cluster.x-k8s.io/is-default"
)
78 changes: 50 additions & 28 deletions pkg/ipam/metal3io/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,26 +130,28 @@ func (m *Metal3IPAM) ReleaseIPs(ctx goctx.Context, owner metav1.Object, pool ipa

func (m *Metal3IPAM) GetAvailableIPPool(ctx goctx.Context, poolMatchLabels map[string]string, clusterMeta metav1.ObjectMeta) (ipam.IPPool, error) {
poolNamespace := getIPPoolNamespace(poolMatchLabels, clusterMeta)
poolName := poolMatchLabels[ipam.ClusterIPPoolNameKey]

// if the specific ip-pool name is provided use that to get the ip-pool
var ipPool ipamv1.IPPool
if poolName, ok := poolMatchLabels[ipam.ClusterIPPoolNameKey]; ok && poolName != "" {
if err := m.Get(ctx, apitypes.NamespacedName{
Namespace: poolNamespace,
Name: poolName,
}, &ipPool); err != nil {
if apierrors.IsNotFound(err) {
return nil, nil
}

return nil, errors.Wrapf(err, "failed to get IPPool %s/%s", poolNamespace, poolName)
}

return toIPPool(ipPool), nil
// 1. If the specific ip-pool name is provided use that to get the ip-pool.
if poolName != "" {
return m.getIPPoolByName(ctx, poolNamespace, poolName)
}

matchLabels := map[string]string{}
// 2. Otherwise use default ip-pool

ipPoolList := &ipamv1.IPPoolList{}
if err := m.List(
ctx,
ipPoolList,
client.InNamespace(clusterMeta.Namespace),
client.MatchingLabels(map[string]string{ipam.DefaultIPPoolKey: "true"})); err != nil {
return nil, err
}
if len(ipPoolList.Items) > 0 {
return toIPPool(ipPoolList.Items[0]), nil
}

matchLabels := map[string]string{ipam.DefaultIPPoolKey: "true"}
// use labels 'ip-pool-group' & 'network-name' to select the ip-pool
if label, ok := poolMatchLabels[ipam.ClusterIPPoolGroupKey]; ok && label != "" {
matchLabels[ipam.ClusterIPPoolGroupKey] = label
Expand All @@ -158,30 +160,50 @@ func (m *Metal3IPAM) GetAvailableIPPool(ctx goctx.Context, poolMatchLabels map[s
matchLabels[ipam.ClusterNetworkNameKey] = label
}

// use default ip-pool
if len(matchLabels) == 0 {
poolNamespace = ipam.DefaultIPPoolNamespace
matchLabels[ipam.DefaultIPPoolKey] = "true"
}

ipPoolList := &ipamv1.IPPoolList{}
ipPoolList = &ipamv1.IPPoolList{}
if err := m.List(
ctx,
ipPoolList,
client.InNamespace(poolNamespace),
client.InNamespace(ipam.DefaultIPPoolNamespace),
client.MatchingLabels(matchLabels)); err != nil {
return nil, err
}

if len(ipPoolList.Items) == 0 {
m.logger.Info("failed to get a matching IPPool")
return nil, nil
}
ipPool = ipPoolList.Items[0]

m.logger.Info(fmt.Sprintf("IPPool %s is available", ipPool.Name))
return toIPPool(ipPoolList.Items[0]), nil
}

// getIPPoolByName returns the IPPool with the specified name.
//
// If IPPool is not found in the specified namespace, will try to find from the
// default namespace.
func (m *Metal3IPAM) getIPPoolByName(ctx goctx.Context, poolNamespace, poolName string) (ipam.IPPool, error) {
var ipPool ipamv1.IPPool
err := m.Get(ctx, apitypes.NamespacedName{
Namespace: poolNamespace,
Name: poolName,
}, &ipPool)
if err == nil {
return toIPPool(ipPool), nil
} else if !apierrors.IsNotFound(err) {
return nil, errors.Wrapf(err, "failed to get IPPool %s/%s", poolNamespace, poolName)
}

// Try the ip-pool default namespace.
err = m.Get(ctx, apitypes.NamespacedName{
Namespace: ipam.DefaultIPPoolNamespace,
Name: poolName,
}, &ipPool)
if err == nil {
return toIPPool(ipPool), nil
} else if apierrors.IsNotFound(err) {
return nil, nil
}

return toIPPool(ipPool), nil
return nil, errors.Wrapf(err, "failed to get IPPool %s/%s", poolNamespace, poolName)
}

func (m *Metal3IPAM) getIPClaim(ctx goctx.Context, pool ipam.IPPool, claimName string) (*ipamv1.IPClaim, error) {
Expand Down

0 comments on commit 302431d

Please sign in to comment.