Skip to content

Commit

Permalink
ShadowPod Status
Browse files Browse the repository at this point in the history
  • Loading branch information
Sharathmk99 authored and adamjensenbot committed May 24, 2023
1 parent ca029ba commit d7d390b
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 14 deletions.
15 changes: 14 additions & 1 deletion apis/virtualkubelet/v1alpha1/shadowpod_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,28 @@ type ShadowPodSpec struct {
Pod corev1.PodSpec `json:"pod,omitempty"`
}

// ShadowPodStatus defines the observed state of ShadowPod.
type ShadowPodStatus struct {
// Phase is the status of this ShadowPod.
// When the pod is created it is checked by the operator, which sets this field same as pod status.
// +kubebuilder:validation:Enum="Pending";"Running";"Succeeded";"Failed";"Unknown"
// +kubebuilder:default="Unknown"
Phase corev1.PodPhase `json:"phase"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +genclient

// ShadowPod is the Schema for the Shadowpods API.
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.phase`
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
type ShadowPod struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ShadowPodSpec `json:"spec,omitempty"`
Spec ShadowPodSpec `json:"spec,omitempty"`
Status ShadowPodStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
16 changes: 16 additions & 0 deletions apis/virtualkubelet/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion deployments/liqo/crds/virtualkubelet.liqo.io_shadowpods.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ spec:
singular: shadowpod
scope: Namespaced
versions:
- name: v1alpha1
- additionalPrinterColumns:
- jsonPath: .status.phase
name: Status
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1alpha1
schema:
openAPIV3Schema:
description: ShadowPod is the Schema for the Shadowpods API.
Expand Down Expand Up @@ -7119,6 +7126,26 @@ spec:
- containers
type: object
type: object
status:
description: ShadowPodStatus defines the observed state of ShadowPod.
properties:
phase:
default: Unknown
description: Phase is the status of this ShadowPod. When the pod is
created it is checked by the operator, which sets this field same
as pod status.
enum:
- Pending
- Running
- Succeeded
- Failed
- Unknown
type: string
required:
- phase
type: object
type: object
served: true
storage: true
subresources:
status: {}
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,11 @@ rules:
- get
- patch
- update
- apiGroups:
- virtualkubelet.liqo.io
resources:
- shadowpods/status
verbs:
- get
- patch
- update

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,10 @@ type Reconciler struct {
Scheme *runtime.Scheme
}

func podShouldBeUpdated(newObj, oldObj client.Object) bool {
changesInLabels := !labels.Equals(newObj.GetLabels(), oldObj.GetLabels())
changesInAnnots := !labels.Equals(newObj.GetAnnotations(), oldObj.GetAnnotations())

return changesInLabels || changesInAnnots
}

// +kubebuilder:rbac:groups=virtualkubelet.liqo.io,resources=shadowpods,verbs=get;list;watch;update;patch;delete
// +kubebuilder:rbac:groups=virtualkubelet.liqo.io,resources=shadowpods/finalizers,verbs=get;update;patch
// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=virtualkubelet.liqo.io,resources=shadowpods/status,verbs=get;update;patch

// Reconcile ShadowPods objects.
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
Expand All @@ -67,6 +61,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return ctrl.Result{}, err
}

if shadowPod.Spec.Pod.RestartPolicy == corev1.RestartPolicyNever &&
(shadowPod.Status.Phase == corev1.PodSucceeded || shadowPod.Status.Phase == corev1.PodFailed) {
klog.V(4).Infof("skip: shadowpod %s already succeeded or failed and restart policy set to Never", shadowPod.GetName())
return ctrl.Result{}, nil
} else if shadowPod.Spec.Pod.RestartPolicy == corev1.RestartPolicyOnFailure && shadowPod.Status.Phase == corev1.PodSucceeded {
klog.V(4).Infof("skip: shadowpod %s already succeeded and restart policy set to OnFailure", shadowPod.GetName())
return ctrl.Result{}, nil
}

// update shadowpod labels to include the "managed-by"
shadowPod.SetLabels(labels.Merge(shadowPod.Labels, labels.Set{consts.ManagedByLabelKey: consts.ManagedByShadowPodValue}))

Expand All @@ -77,7 +80,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return ctrl.Result{}, err
} else if err == nil {
// Update Labels and Annotations
klog.V(4).Infof("pod %q found running, will update it with labels: %v and annotations: %v",
klog.V(4).Infof("pod %q found in cluster, will update it with labels: %v and annotations: %v",
klog.KObj(&existingPod), existingPod.Labels, existingPod.Annotations)

// Create Apply object for Existing Pod
Expand All @@ -90,6 +93,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return ctrl.Result{}, err
}

// Update ShadowPod status same as Pod status
shadowPod.Status.Phase = existingPod.Status.DeepCopy().Phase
if newErr := r.Client.Status().Update(ctx, &shadowPod); newErr != nil {
klog.Error(newErr)
return ctrl.Result{}, newErr
}

klog.Infof("updated pod %q with success", klog.KObj(&existingPod))

return ctrl.Result{}, nil
Expand Down Expand Up @@ -124,7 +134,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager, workers int) error {
reconciledPredicates := predicate.Funcs{
DeleteFunc: func(e event.DeleteEvent) bool { return true },
CreateFunc: func(e event.CreateEvent) bool { return false },
UpdateFunc: func(e event.UpdateEvent) bool { return podShouldBeUpdated(e.ObjectNew, e.ObjectOld) },
UpdateFunc: func(e event.UpdateEvent) bool { return true },
GenericFunc: func(e event.GenericEvent) bool { return false },
}
return ctrl.NewControllerManagedBy(mgr).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ var _ = Describe("Reconcile", func() {
err error
buffer *bytes.Buffer

testShadowPod vkv1alpha1.ShadowPod
testPod corev1.Pod
testShadowPod vkv1alpha1.ShadowPod
testShadowPodSuccess vkv1alpha1.ShadowPod
testPod corev1.Pod
)

BeforeEach(func() {
Expand Down Expand Up @@ -83,6 +84,34 @@ var _ = Describe("Reconcile", func() {
},
}},
},
Status: vkv1alpha1.ShadowPodStatus{
Phase: corev1.PodUnknown,
},
}
testShadowPodSuccess = vkv1alpha1.ShadowPod{
ObjectMeta: metav1.ObjectMeta{
Name: shadowPodName,
Namespace: shadowPodNamespace,
Labels: map[string]string{
"label1-key": "label1-value",
"label2-key": "label2-value",
},
Annotations: map[string]string{
"annotation1-key": "annotation1-value",
"annotation2-key": "annotation2-value",
},
},
Spec: vkv1alpha1.ShadowPodSpec{
Pod: corev1.PodSpec{Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx",
},
}},
},
Status: vkv1alpha1.ShadowPodStatus{
Phase: corev1.PodSucceeded,
},
}

testPod = corev1.Pod{
Expand All @@ -91,6 +120,9 @@ var _ = Describe("Reconcile", func() {
Namespace: testShadowPod.Namespace,
},
Spec: testShadowPod.Spec.Pod,
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
}
})

Expand Down Expand Up @@ -125,7 +157,7 @@ var _ = Describe("Reconcile", func() {
It("should align pod and shadowpod", func() {
Expect(err).NotTo(HaveOccurred())
Expect(res).To(BeZero())
Expect(buffer.String()).To(ContainSubstring(fmt.Sprintf("pod %q found running, will update it with", klog.KObj(&testPod))))
Expect(buffer.String()).To(ContainSubstring(fmt.Sprintf("pod %q found in cluster, will update it with", klog.KObj(&testPod))))
})

It("should update pod metadata to shadowpod metadata", func() {
Expand Down Expand Up @@ -187,6 +219,17 @@ var _ = Describe("Reconcile", func() {
Expect(podContainer.Image).To(Equal(shadowPodContainer.Image))
})
})

When("pod is already completed or failed, shouldn't recreate pod", func() {
BeforeEach(func() {
Expect(k8sClient.Create(ctx, &testShadowPodSuccess)).To(Succeed())
})

It("should not create pod because shadowpod status is success", func() {
pod := corev1.Pod{}
Expect(k8sClient.Get(ctx, req.NamespacedName, &pod)).To(BeNil())
})
})
})

func deleteAllShadowPodsAndPods(ctx context.Context, ns string) {
Expand Down

0 comments on commit d7d390b

Please sign in to comment.