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

reclaim of static ip #28

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
57 changes: 57 additions & 0 deletions controllers/vspherecluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ func (r *VSphereClusterReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, util.IgnoreNotFound(err)
}

// Handle deleted clusters
if !vSphereCluster.DeletionTimestamp.IsZero() {
res, err = r.reconcileDelete(cluster, vSphereCluster)
if err != nil {
log.Error(err, "failed to reconcileDelete VSphereCluster")
}

return *res, err
}

res, err = r.reconcileVSphereClusterControlPlaneEndpoint(cluster, vSphereCluster)
if err != nil {
log.Error(err, "failed to reconcile VSphereCluster control plane endpoint")
Expand Down Expand Up @@ -139,6 +149,53 @@ func (r *VSphereClusterReconciler) reconcileVSphereClusterControlPlaneEndpoint(c
return &ctrl.Result{}, nil
}

func (r *VSphereClusterReconciler) reconcileDelete(cluster *capi.Cluster, vSphereCluster *infrav1.VSphereCluster) (*ctrl.Result, error) {
if vSphereCluster == nil {
r.Log.V(0).Info("invalid VSphereCluster, skipping reconcile control plane endpoint")
return &ctrl.Result{}, nil
}

log := r.Log.WithValues("vsphereCluster", vSphereCluster.Name, "namespace", vSphereCluster.Namespace)
log.V(0).Info("reconcileDelete control plane endpoint address for VSphereCluster")

if len(vSphereCluster.Spec.ControlPlaneEndpoint.Host) <= 0 {
log.V(0).Info("control plane endpoint is not allocated for the VSphereCluster", "vSphereCluster", vSphereCluster.Name)
return &ctrl.Result{}, nil
}

newIpamFunc, ok := factory.IpamFactory[ipam.IpamTypeMetal3io]
if !ok {
log.V(0).Info("ipam type not supported")
return &ctrl.Result{}, nil
}

ipamFunc := newIpamFunc(r.Client, log)

ipPool, err := ipamFunc.GetAvailableIPPool(vSphereCluster.Labels, cluster.ObjectMeta)
if err != nil {
log.Error(err, "failed to get an available IPPool")
return &ctrl.Result{}, nil
}
if ipPool == nil {
log.V(0).Info("waiting for IPPool to be available")
return &ctrl.Result{}, nil
}

ipName := vSphereCluster.Name
ip, err := ipamFunc.GetIP(ipName, ipPool)
if err != nil {
return &ctrl.Result{}, errors.Wrapf(err, "failed to get allocated IP address for VSphereCluster %s", vSphereCluster.Name)
}

if ip != nil {
if err := ipamFunc.DeallocateIP(ipName, ipPool, vSphereCluster); err != nil {
return &ctrl.Result{}, errors.Wrapf(err, "failed to deallocate IP address for VSphereCluster %s", vSphereCluster.Name)
}
}

return &ctrl.Result{}, nil
}

func (r *VSphereClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&infrav1.VSphereCluster{}).
Expand Down
75 changes: 75 additions & 0 deletions controllers/vspheremachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ func (r *VSphereMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, nil
}

if !vsphereMachine.ObjectMeta.DeletionTimestamp.IsZero() {
res, err = r.reconcileDelete(cluster, vsphereMachine)

if err != nil {
log.V(0).Info("IPClaim delete was uncessful %s", err.Error())
return ctrl.Result{}, err
}
return *res, nil
}

res, err = r.reconcileVSphereMachineIPAddress(cluster, vsphereMachine)
if err != nil {
log.Error(err, "failed to reconcile VSphereMachine IP")
Expand All @@ -96,6 +106,71 @@ func (r *VSphereMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return *res, err
}

func (r *VSphereMachineReconciler) reconcileDelete(cluster *capi.Cluster, vSphereMachine *infrav1.VSphereMachine) (*ctrl.Result, error) {
if vSphereMachine == nil {
r.Log.V(0).Info("invalid VSphereMachine, skipping reconcile delete IPAddress")
return &ctrl.Result{}, nil
}

log := r.Log.WithValues("vsphereMachine", vSphereMachine.Name, "namespace", vSphereMachine.Namespace)
devices := vSphereMachine.Spec.VirtualMachineCloneSpec.Network.Devices
log.V(0).Info("reconcile IP address for VSphereMachine")
if len(devices) == 0 {
log.V(0).Info("no network device found for VSphereMachine")
return &ctrl.Result{}, nil
}

if util.IsMachineIPAllocationDHCP(devices) {
log.V(0).Info("VSphereMachine has allocation type DHCP")
return &ctrl.Result{}, nil
}

newIpamFunc, ok := factory.IpamFactory[ipam.IpamTypeMetal3io]
if !ok {
log.V(0).Info("ipam type not supported")
return &ctrl.Result{}, nil
}

ipamFunc := newIpamFunc(r.Client, log)

for i := range devices {
if util.IsDeviceIPAllocationDHCP(devices[i]) || len(devices[i].IPAddrs) > 0 {
continue
}

poolMatchLabels, err := r.getIPPoolMatchLabels(r.Client, vSphereMachine)
if err != nil {
log.Error(err, "failed to get IPPool match labels")
return &ctrl.Result{}, nil
}
ipPool, err := ipamFunc.GetAvailableIPPool(poolMatchLabels, cluster.ObjectMeta)
if err != nil {
log.Error(err, "failed to get an available IPPool")
return &ctrl.Result{}, nil
}
if ipPool == nil {
log.V(0).Info("waiting for IPPool to be available")
return &ctrl.Result{}, nil
}

ipName := util.GetFormattedClaimName(vSphereMachine.Name, i)
ip, err := ipamFunc.GetIP(ipName, ipPool)
if err != nil {
return &ctrl.Result{}, errors.Wrapf(err, "failed to get allocated IP address for VSphereMachine %s", vSphereMachine.Name)
}

if ip != nil {
if err := ipamFunc.DeallocateIP(ipName, ipPool, vSphereMachine); err != nil {
return &ctrl.Result{}, errors.Wrapf(err, "failed to allocate IP address for VSphereMachine: %s", vSphereMachine.Name)
}
}
}

log.V(0).Info("successfully reconcile deleted IP address for VSphereMachine")

return &ctrl.Result{}, nil
}

func (r *VSphereMachineReconciler) reconcileVSphereMachineIPAddress(cluster *capi.Cluster, vSphereMachine *infrav1.VSphereMachine) (*ctrl.Result, error) {
if vSphereMachine == nil {
r.Log.V(0).Info("invalid VSphereMachine, skipping reconcile IPAddress")
Expand Down
33 changes: 28 additions & 5 deletions pkg/ipam/metal3io/metal3io_ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (m Metal3IPAM) AllocateIP(ipName string, pool ipam.IPPool, ownerObj runtime
m.log.V(0).Info(fmt.Sprintf("allocate IP %s", ipName))

//check if ip claim already exists
ic, err := getIPClaim(m.Client, pool, ipName)
ic, err := getIPClaim(m.Client, pool.GetNamespace(), ipName)
if err != nil {
m.log.V(0).Info(fmt.Sprintf("failed to get IPClaim %s", ipName))
return nil, err
Expand All @@ -66,7 +66,30 @@ func (m Metal3IPAM) AllocateIP(ipName string, pool ipam.IPPool, ownerObj runtime
return nil, nil
}

func (m Metal3IPAM) DeallocateIP(name string, pool ipam.IPPool, ownerObj runtime.Object) error {
func (m Metal3IPAM) DeallocateIP(ipName string, pool ipam.IPPool, ownerObj runtime.Object) error {
o := util.GetObjRef(ownerObj)
m.log.V(0).Info(fmt.Sprintf("Deallocate IP %s Name %s Namespace %s", ipName, o.Name, o.Namespace))

//check if ip claim exists
ic, err := getIPClaim(m.Client, o.Namespace, ipName)
if err != nil {
m.log.V(0).Info(fmt.Sprintf("failed to get IPClaim %s", ipName))
return err
}

//if IPClaim doesn't exists,then cant delete.
if ic == nil {
m.log.V(0).Info(fmt.Sprintf("IPClaim %s doesn't exists, skipping deletion", ipName))
return nil
}

//delete ip claim
if err := m.Client.Delete(context.Background(), ic); err != nil {
if !apierrors.IsAlreadyExists(err) {
return errors.Wrapf(err, "failed to delete IPClaim %s", ipName)
}
}

return nil
}

Expand Down Expand Up @@ -128,7 +151,7 @@ func getIPPoolNamespace(meta metav1.ObjectMeta) string {
}

func getIPAddress(cli client.Client, pool ipam.IPPool, ipName string, log logr.Logger) (ipam.IPAddress, error) {
ic, err := getIPClaim(cli, pool, ipName)
ic, err := getIPClaim(cli, pool.GetNamespace(), ipName)
if err != nil {
log.V(0).Info(fmt.Sprintf("failed to get IPClaim %s", ipName))
return nil, err
Expand All @@ -153,9 +176,9 @@ func getIPAddress(cli client.Client, pool ipam.IPPool, ipName string, log logr.L
return convertToMetal3ioIP(*ip, searchDomains), nil
}

func getIPClaim(cli client.Client, pool ipam.IPPool, claimName string) (*ipamv1.IPClaim, error) {
func getIPClaim(cli client.Client, poolNamespace string, claimName string) (*ipamv1.IPClaim, error) {
ic := &ipamv1.IPClaim{}
icKey := types.NamespacedName{Namespace: pool.GetNamespace(), Name: claimName}
icKey := types.NamespacedName{Namespace: poolNamespace, Name: claimName}
if err := cli.Get(context.Background(), icKey, ic); err != nil {
return nil, util.IgnoreNotFound(err)
}
Expand Down