Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func main() {
}

vmipLogger := logger.NewControllerLogger(vmip.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList)
if _, err = vmip.NewController(ctx, mgr, vmipLogger, virtualMachineCIDRs); err != nil {
if _, err = vmip.NewController(ctx, mgr, virtClient, vmipLogger, virtualMachineCIDRs); err != nil {
log.Error(err.Error())
os.Exit(1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ const (
// LabelVirtualMachineUID is a label to link VirtualMachineIPAddress to VirtualMachine.
LabelVirtualMachineUID = LabelsPrefix + "/virtual-machine-uid"

// LabelVirtualMachineIPAddressUID is a label to link VirtualMachineIPAddressLease to VirtualMachineIPAddress.
LabelVirtualMachineIPAddressUID = LabelsPrefix + "/virtual-machine-ip-address-uid"

UploaderServiceLabel = "service"

// AppKubernetesManagedByLabel is the Kubernetes recommended managed-by label.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ const (
IndexFieldVMByCVI = "spec.blockDeviceRefs.ClusterVirtualImage"
IndexFieldVMByNode = "status.node"

IndexFieldVMIPLeaseByVMIP = "spec.virtualMachineIPAddressRef.Name"

IndexFieldVDByVDSnapshot = "vd,spec.DataSource.ObjectRef.Name,.Kind=VirtualDiskSnapshot"
IndexFieldVIByVDSnapshot = "vi,spec.DataSource.ObjectRef.Name,.Kind=VirtualDiskSnapshot"
IndexFieldCVIByVDSnapshot = "cvi,spec.DataSource.ObjectRef.Name,.Kind=VirtualDiskSnapshot"
Expand All @@ -62,7 +60,6 @@ var IndexGetters = []IndexGetter{
IndexVMByVI,
IndexVMByCVI,
IndexVMByNode,
IndexVMIPLeaseByVMIP,
IndexVMSnapshotByVM,
IndexVMSnapshotByVDSnapshot,
IndexVMRestoreByVMSnapshot,
Expand Down Expand Up @@ -140,13 +137,3 @@ func getBlockDeviceNamesByKind(obj client.Object, kind virtv2.BlockDeviceKind) [
}
return res
}

func IndexVMIPLeaseByVMIP() (obj client.Object, field string, extractValue client.IndexerFunc) {
return &virtv2.VirtualMachineIPAddressLease{}, IndexFieldVMIPLeaseByVMIP, func(object client.Object) []string {
lease, ok := object.(*virtv2.VirtualMachineIPAddressLease)
if !ok || lease == nil {
return nil
}
return []string{lease.Spec.VirtualMachineIPAddressRef.Name}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
k8snet "k8s.io/utils/net"

"github.com/deckhouse/deckhouse/pkg/log"

"github.com/deckhouse/virtualization-controller/pkg/common/ip"
)

Expand Down Expand Up @@ -94,6 +95,7 @@ func (s IpAddressService) AllocateNewIP(allocatedIPs ip.AllocatedIPs) (string, e
}

if _, ok := allocatedIPs[ip.String()]; !ok {

return ip.String(), nil
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"time"

corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
"github.com/deckhouse/virtualization-controller/pkg/common/ip"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
"github.com/deckhouse/virtualization-controller/pkg/controller/service"
Expand Down Expand Up @@ -56,20 +60,9 @@ func NewIPLeaseHandler(client client.Client, ipAddressService *service.IpAddress
func (h IPLeaseHandler) Handle(ctx context.Context, state state.VMIPState) (reconcile.Result, error) {
log, ctx := logger.GetHandlerContext(ctx, IpLeaseHandlerName)

vmip := state.VirtualMachineIP()
vmipStatus := &vmip.Status

lease, err := state.VirtualMachineIPLease(ctx)
if err != nil {
return reconcile.Result{}, err
}
condition, _ := conditions.GetCondition(vmipcondition.BoundType, vmipStatus.Conditions)
vmip, lease := state.VirtualMachineIP(), state.VirtualMachineIPLease()

switch {
case lease == nil && vmipStatus.Address != "" && condition.Reason != vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists.String():
log.Info("Lease by name not found: waiting for the lease to be available")
return reconcile.Result{}, nil

case lease == nil:
log.Info("No Lease for VirtualMachineIP: create the new one", "type", vmip.Spec.Type, "address", vmip.Spec.StaticIP)
return h.createNewLease(ctx, state)
Expand All @@ -78,96 +71,98 @@ func (h IPLeaseHandler) Handle(ctx context.Context, state state.VMIPState) (reco
log.Info("Lease is not ready: waiting for the lease")
return reconcile.Result{}, nil

case vmip.Status.Address == "":
vmip.Status.Address = ip.LeaseNameToIP(lease.Name)
return reconcile.Result{}, nil

case util.IsBoundLease(lease, vmip):
log.Info("Lease already exists, VirtualMachineIP ref is valid")
log.Info("Lease is bound, VirtualMachineIP ref is valid")
return reconcile.Result{}, nil

case lease.Status.Phase == virtv2.VirtualMachineIPAddressLeasePhaseBound:
log.Info("Lease is bounded to another VirtualMachineIP: recreate VirtualMachineIP when the lease is released")
return reconcile.Result{}, nil

default:
log.Info("Lease is released: set binding")

if lease.Spec.VirtualMachineIPAddressRef.Namespace != vmip.Namespace {
log.Warn(fmt.Sprintf("The VirtualMachineIPLease belongs to a different namespace: %s", lease.Spec.VirtualMachineIPAddressRef.Namespace))
h.recorder.Event(vmip, corev1.EventTypeWarning, vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists.String(), "The VirtualMachineIPLease belongs to a different namespace")

return reconcile.Result{}, nil
}
return h.updateLease(ctx, lease, vmip, log)
}
}

lease.Spec.VirtualMachineIPAddressRef = &virtv2.VirtualMachineIPAddressLeaseIpAddressRef{
Name: vmip.Name,
Namespace: vmip.Namespace,
}
func (h IPLeaseHandler) updateLease(ctx context.Context, lease *virtv2.VirtualMachineIPAddressLease, vmip *virtv2.VirtualMachineIPAddress, log *slog.Logger) (reconcile.Result, error) {
log.Info("Lease is released: set binding")

err := h.client.Update(ctx, lease)
if err != nil {
return reconcile.Result{}, err
}
if lease.Spec.VirtualMachineIPAddressRef.Namespace != vmip.Namespace {
log.Warn(fmt.Sprintf("The VirtualMachineIPLease belongs to a different namespace: %s", lease.Spec.VirtualMachineIPAddressRef.Namespace))
h.recorder.Event(vmip, corev1.EventTypeWarning, vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists.String(), "The VirtualMachineIPLease belongs to a different namespace")

vmipStatus.Address = ip.LeaseNameToIP(lease.Name)
return reconcile.Result{}, nil
}

lease.Spec.VirtualMachineIPAddressRef = &virtv2.VirtualMachineIPAddressLeaseIpAddressRef{
Name: vmip.Name,
Namespace: vmip.Namespace,
}
annotations.AddLabel(lease, annotations.LabelVirtualMachineIPAddressUID, string(vmip.GetUID()))

return reconcile.Result{}, h.client.Update(ctx, lease)
}

func (h IPLeaseHandler) createNewLease(ctx context.Context, state state.VMIPState) (reconcile.Result, error) {
log := logger.FromContext(ctx)

vmip := state.VirtualMachineIP()
vmipStatus := &vmip.Status

ipAddress := ""
if vmip.Spec.Type == virtv2.VirtualMachineIPAddressTypeAuto {
log.Info("allocate the new VirtualMachineIP address")
var err error
vmipStatus.Address, err = h.ipService.AllocateNewIP(state.AllocatedIPs())
ipAddress, err = h.ipService.AllocateNewIP(state.AllocatedIPs())
if err != nil {
return reconcile.Result{}, err
}
} else {
vmipStatus.Address = vmip.Spec.StaticIP
ipAddress = vmip.Spec.StaticIP
}

err := h.ipService.IsAvailableAddress(vmipStatus.Address, state.AllocatedIPs())
err := h.ipService.IsAvailableAddress(ipAddress, state.AllocatedIPs())
if err != nil {
vmipStatus.Address = ""
msg := fmt.Sprintf("the VirtualMachineIP cannot be created: %s", err.Error())
log.Info(msg)
log.Warn(msg)

conditionBound := conditions.NewConditionBuilder(vmipcondition.BoundType).
Generation(vmip.GetGeneration())

switch {
case errors.Is(err, service.ErrIPAddressOutOfRange):
vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending
msg := fmt.Sprintf("The requested address %s is out of the valid range.", vmip.Spec.StaticIP)
vmip.Status.Phase = virtv2.VirtualMachineIPAddressPhasePending
msg = fmt.Sprintf("The requested address %s is out of the valid range.", vmip.Spec.StaticIP)
conditionBound.Status(metav1.ConditionFalse).
Reason(vmipcondition.VirtualMachineIPAddressIsOutOfTheValidRange).
Message(msg)
h.recorder.Event(vmip, corev1.EventTypeWarning, virtv2.ReasonFailed, msg)
case errors.Is(err, service.ErrIPAddressAlreadyExist):
vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending
msg := fmt.Sprintf("VirtualMachineIPAddressLease %s is bound to another VirtualMachineIPAddress.",
ip.IpToLeaseName(vmipStatus.Address))
vmip.Status.Phase = virtv2.VirtualMachineIPAddressPhasePending
msg = fmt.Sprintf("VirtualMachineIPAddressLease %s is bound to another VirtualMachineIPAddress.",
ip.IpToLeaseName(ipAddress))
conditionBound.Status(metav1.ConditionFalse).
Reason(vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists).
Message(msg)
h.recorder.Event(vmip, corev1.EventTypeWarning, virtv2.ReasonBound, msg)
}
conditions.SetCondition(conditionBound, &vmipStatus.Conditions)
conditions.SetCondition(conditionBound, &vmip.Status.Conditions)
return reconcile.Result{}, nil
}

leaseName := ip.IpToLeaseName(vmipStatus.Address)
leaseName := ip.IpToLeaseName(ipAddress)

log.Info("Create lease",
"leaseName", leaseName,
"refName", vmip.Name,
"refNamespace", vmip.Namespace,
log.Info("Create lease", "leaseName", leaseName,
"refName", vmip.Name, "refNamespace", vmip.Namespace,
)

err = h.client.Create(ctx, &virtv2.VirtualMachineIPAddressLease{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
annotations.LabelVirtualMachineIPAddressUID: string(vmip.GetUID()),
},
Name: leaseName,
},
Spec: virtv2.VirtualMachineIPAddressLeaseSpec{
Expand All @@ -178,6 +173,11 @@ func (h IPLeaseHandler) createNewLease(ctx context.Context, state state.VMIPStat
},
})
if err != nil {
if k8serrors.IsAlreadyExists(err) {
log.Warn("Lease already exists: requeue 2s")
return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
}

return reconcile.Result{}, err
}

Expand Down
Loading
Loading