Skip to content

Commit

Permalink
Added a callback to provide additional pre-conditions for installation
Browse files Browse the repository at this point in the history
Signed-off-by: jubittajohn <jujohn@redhat.com>

Added unit test

Signed-off-by: jubittajohn <jujohn@redhat.com>

Preconditions are only evaluated when the installer pod isn't already present

Signed-off-by: jubittajohn <jujohn@redhat.com>
  • Loading branch information
jubittajohn committed Jul 9, 2024
1 parent aee040b commit 4b49b84
Show file tree
Hide file tree
Showing 3 changed files with 390 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ type InstallerController struct {
clock clock.Clock
installerBackOff func(count int) time.Duration
fallbackBackOff func(count int) time.Duration

installPrecondition StaticPodInstallerPreconditionsFuncType
}

// InstallerPodMutationFunc is a function that has a chance at changing the installer pod before it is created
Expand Down Expand Up @@ -128,6 +130,14 @@ func (c *InstallerController) WithStartupMonitorSupport(startupMonitorEnabled fu
return c
}

// StaticPodInstallerPreconditionsFuncType checks if installPrecondition is met (is true) and then proceeeds with creation of installer pod
type StaticPodInstallerPreconditionsFuncType func(ctx context.Context) (bool, error)

func (c *InstallerController) WithInstallPrecondition(installPrecondition StaticPodInstallerPreconditionsFuncType) *InstallerController {
c.installPrecondition = installPrecondition
return c
}

// staticPodState is the status of a static pod that has been installed to a node.
type staticPodState int

Expand Down Expand Up @@ -478,14 +488,19 @@ func (c *InstallerController) manageInstallationPods(ctx context.Context, operat
}
}

if err := c.ensureInstallerPod(ctx, operatorSpec, currNodeState); err != nil {
requeue, err := c.ensureInstallerPod(ctx, operatorSpec, currNodeState)
if err != nil {
c.eventRecorder.Warningf("InstallerPodFailed", "Failed to create installer pod for revision %d count %d on node %q: %v",
currNodeState.TargetRevision, currNodeState.LastFailedCount, currNodeState.NodeName, err)
// if a newer revision is pending, continue, so we retry later with the latest available revision
if !(operatorStatus.LatestAvailableRevision > currNodeState.TargetRevision) {
return true, 0, err
}
}
if requeue {
klog.V(4).Infof("Requeuing the creation of installer pod for revision %d on node %q", currNodeState.TargetRevision, currNodeState.NodeName)
return true, 0, nil
}
}

newCurrNodeState, _, reason, err := c.newNodeStateForInstallInProgress(ctx, currNodeState, operatorStatus.LatestAvailableRevision)
Expand Down Expand Up @@ -851,7 +866,27 @@ func getInstallerPodName(ns *operatorv1.NodeStatus) string {
}

// ensureInstallerPod creates the installer pod with the secrets required to if it does not exist already
func (c *InstallerController) ensureInstallerPod(ctx context.Context, operatorSpec *operatorv1.StaticPodOperatorSpec, ns *operatorv1.NodeStatus) error {
// returns whether or not to requeue and if an error happened while ensuring the installer pod
func (c *InstallerController) ensureInstallerPod(ctx context.Context, operatorSpec *operatorv1.StaticPodOperatorSpec, ns *operatorv1.NodeStatus) (bool, error) {
// checks if a new installer pod should be created based on the preconditions being met
// preconditions are only evaluated when the installer pod isn't already present
installerPodName := getInstallerPodName(ns)
_, err := c.podsGetter.Pods(c.targetNamespace).Get(ctx, installerPodName, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
if c.installPrecondition != nil {
shouldInstall, err := c.installPrecondition(ctx)
if err != nil {
return true, err
}
if !shouldInstall {
klog.Infof("Preconditions not met, skipping the creation of installer pod %s", installerPodName)
return true, nil
}
}
} else if err != nil {
return true, err
}

pod := resourceread.ReadPodV1OrDie(podTemplate)

pod.Namespace = c.targetNamespace
Expand All @@ -862,19 +897,19 @@ func (c *InstallerController) ensureInstallerPod(ctx context.Context, operatorSp

ownerRefs, err := c.ownerRefsFn(ctx, ns.TargetRevision)
if err != nil {
return fmt.Errorf("unable to set installer pod ownerrefs: %+v", err)
return true, fmt.Errorf("unable to set installer pod ownerrefs: %+v", err)
}
pod.OwnerReferences = ownerRefs

if c.configMaps[0].Optional {
return fmt.Errorf("pod configmap %s is required, cannot be optional", c.configMaps[0].Name)
return true, fmt.Errorf("pod configmap %s is required, cannot be optional", c.configMaps[0].Name)
}

// if the startup monitor is enabled we need to acquire an exclusive lock
// to coordinate the work between the installer and the monitor
withStartupMonitorSupport, err := c.startupMonitorEnabled()
if err != nil {
return fmt.Errorf("unable to determine if the startup monitor should be enabled: %v", err)
return true, fmt.Errorf("unable to determine if the startup monitor should be enabled: %v", err)
}

args := []string{
Expand Down Expand Up @@ -926,12 +961,14 @@ func (c *InstallerController) ensureInstallerPod(ctx context.Context, operatorSp
// Some owners need to change aspects of the pod. Things like arguments for instance
for _, fn := range c.installerPodMutationFns {
if err := fn(pod, ns.NodeName, operatorSpec, ns.TargetRevision); err != nil {
return err
return true, err
}
}

_, _, err = resourceapply.ApplyPod(ctx, c.podsGetter, c.eventRecorder, pod)
return err
if _, _, err = resourceapply.ApplyPod(ctx, c.podsGetter, c.eventRecorder, pod); err != nil {
return true, err
}
return false, nil
}

func (c *InstallerController) setOwnerRefs(ctx context.Context, revision int32) ([]metav1.OwnerReference, error) {
Expand Down
Loading

0 comments on commit 4b49b84

Please sign in to comment.