Skip to content

Commit 5429888

Browse files
committed
fix for issue # 119
1 parent e568f6c commit 5429888

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

api/v1alpha1/sandbox_types.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,46 @@ type SandboxSpec struct {
119119
Replicas *int32 `json:"replicas,omitempty"`
120120
}
121121

122+
123+
// SandboxPhase is a label for the condition of a sandbox at the current time.
124+
type SandboxPhase string
125+
126+
// These are the valid phases of a sandbox.
127+
const (
128+
// SandboxPending means the sandbox has been accepted by the system, but one or more of the components
129+
// has not been created. This includes time before pods have been scheduled as well as time spent
130+
// pulling images over the network, which can take a while.
131+
SandboxPending SandboxPhase = "Pending"
132+
// SandboxRunning means the sandbox has been bound to a node and all of the containers have been started.
133+
// At least one container is still running or is in the process of being restarted.
134+
SandboxRunning SandboxPhase = "Running"
135+
// SandboxPaused means the sandbox has been paused.
136+
SandboxPaused SandboxPhase = "Paused"
137+
// SandboxTerminating means the sandbox is terminating.
138+
SandboxTerminating SandboxPhase = "Terminating"
139+
// SandboxFailed means the sandbox has terminated with an error.
140+
SandboxFailed SandboxPhase = "Failed"
141+
)
142+
122143
// SandboxStatus defines the observed state of Sandbox.
123144
type SandboxStatus struct {
145+
// The phase of a Sandbox is a simple, high-level summary of where the Sandbox is in its lifecycle.
146+
// The conditions array, the reason and message fields, and the individual container status arrays contain
147+
// more detail about the pod's status.
148+
// There are five possible phase values:
149+
//
150+
// Pending: The Sandbox has been accepted by the Kubernetes system, but one or more of the components
151+
// has not been created. This includes time before pods have been scheduled as well as time spent pulling
152+
// images over the network, which can take a while.
153+
// Running: The Sandbox has been bound to a node, and all of the Pods have been created. At least
154+
// one Pod is still running, or is in the process of being restarted.
155+
// Paused: The Sandbox has been paused.
156+
// Terminating: The Sandbox is terminating.
157+
// Failed: The Sandbox has terminated with an error.
158+
//
159+
// +optional
160+
Phase SandboxPhase `json:"phase,omitempty"`
161+
124162
// FQDN that is valid for default cluster settings
125163
// Limitation: Hardcoded to the domain .cluster.local
126164
// e.g. sandbox-example.default.svc.cluster.local
@@ -140,6 +178,7 @@ type SandboxStatus struct {
140178
LabelSelector string `json:"selector,omitempty"`
141179
}
142180

181+
143182
// +kubebuilder:object:root=true
144183
// +kubebuilder:subresource:status
145184
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector

controllers/sandbox_controller.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,13 @@ func (r *SandboxReconciler) reconcileChildResources(ctx context.Context, sandbox
141141
sandbox.Status.Replicas = 1
142142
sandbox.Status.LabelSelector = fmt.Sprintf("%s=%s", sandboxLabel, NameHash(sandbox.Name))
143143
}
144+
sandbox.Status.Phase = r.calculatePhase(sandbox, pod)
144145

145146
// Reconcile Service
146147
svc, err := r.reconcileService(ctx, sandbox, nameHash)
147148
allErrors = errors.Join(allErrors, err)
148149

150+
149151
// compute and set overall Ready condition
150152
readyCondition := r.computeReadyCondition(sandbox, allErrors, svc, pod)
151153
meta.SetStatusCondition(&sandbox.Status.Conditions, readyCondition)
@@ -213,6 +215,29 @@ func (r *SandboxReconciler) computeReadyCondition(sandbox *sandboxv1alpha1.Sandb
213215
return readyCondition
214216
}
215217

218+
func (r *SandboxReconciler) calculatePhase(sandbox *sandboxv1alpha1.Sandbox, pod *corev1.Pod) sandboxv1alpha1.SandboxPhase {
219+
if sandbox.Spec.Replicas != nil && *sandbox.Spec.Replicas == 0 {
220+
return sandboxv1alpha1.SandboxPaused
221+
}
222+
223+
if pod == nil {
224+
return sandboxv1alpha1.SandboxPending
225+
}
226+
227+
switch pod.Status.Phase {
228+
case corev1.PodRunning:
229+
return sandboxv1alpha1.SandboxRunning
230+
case corev1.PodPending:
231+
return sandboxv1alpha1.SandboxPending
232+
case corev1.PodFailed:
233+
return sandboxv1alpha1.SandboxFailed
234+
case corev1.PodSucceeded:
235+
return sandboxv1alpha1.SandboxTerminating
236+
}
237+
return sandboxv1alpha1.SandboxPending
238+
}
239+
240+
216241
func (r *SandboxReconciler) updateStatus(ctx context.Context, oldStatus *sandboxv1alpha1.SandboxStatus, sandbox *sandboxv1alpha1.Sandbox) error {
217242
log := log.FromContext(ctx)
218243

@@ -431,6 +456,7 @@ func (r *SandboxReconciler) handleSandboxExpiry(ctx context.Context, sandbox *sa
431456
Message: "Sandbox has expired",
432457
})
433458

459+
sandbox.Status.Phase = sandboxv1alpha1.SandboxTerminating
434460
sandbox.Status.Replicas = 0
435461
sandbox.Status.LabelSelector = ""
436462

controllers/sandbox_controller_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ func TestReconcile(t *testing.T) {
227227
},
228228
// Verify Sandbox status
229229
wantStatus: sandboxv1alpha1.SandboxStatus{
230+
Phase: sandboxv1alpha1.SandboxPending,
230231
Service: sandboxName,
231232
ServiceFQDN: "sandbox-name.sandbox-ns.svc.cluster.local",
232233
Replicas: 1,
@@ -320,6 +321,7 @@ func TestReconcile(t *testing.T) {
320321
},
321322
// Verify Sandbox status
322323
wantStatus: sandboxv1alpha1.SandboxStatus{
324+
Phase: sandboxv1alpha1.SandboxPending,
323325
Service: sandboxName,
324326
ServiceFQDN: "sandbox-name.sandbox-ns.svc.cluster.local",
325327
Replicas: 1,
@@ -406,6 +408,91 @@ func TestReconcile(t *testing.T) {
406408
},
407409
},
408410
},
411+
{
412+
name: "sandbox spec with 0 replicas",
413+
// Input sandbox spec
414+
sandboxSpec: sandboxv1alpha1.SandboxSpec{
415+
Replicas: ptr.To(int32(0)),
416+
PodTemplate: sandboxv1alpha1.PodTemplate{
417+
Spec: corev1.PodSpec{
418+
Containers: []corev1.Container{
419+
{
420+
Name: "test-container",
421+
},
422+
},
423+
},
424+
},
425+
},
426+
// Verify Sandbox status
427+
wantStatus: sandboxv1alpha1.SandboxStatus{
428+
Phase: sandboxv1alpha1.SandboxPaused,
429+
Service: sandboxName,
430+
ServiceFQDN: "sandbox-name.sandbox-ns.svc.cluster.local",
431+
Replicas: 0,
432+
LabelSelector: "",
433+
Conditions: []metav1.Condition{
434+
{
435+
Type: "Ready",
436+
Status: "True",
437+
ObservedGeneration: 1,
438+
Reason: "DependenciesReady",
439+
Message: "Pod does not exist, replicas is 0; Service Exists",
440+
},
441+
},
442+
},
443+
wantObjs: []client.Object{
444+
// Verify Service
445+
&corev1.Service{
446+
ObjectMeta: metav1.ObjectMeta{
447+
Name: sandboxName,
448+
Namespace: sandboxNs,
449+
ResourceVersion: "1",
450+
Labels: map[string]string{
451+
"agents.x-k8s.io/sandbox-name-hash": "ab179450",
452+
},
453+
OwnerReferences: []metav1.OwnerReference{sandboxControllerRef(sandboxName)},
454+
},
455+
Spec: corev1.ServiceSpec{
456+
Selector: map[string]string{
457+
"agents.x-k8s.io/sandbox-name-hash": "ab179450",
458+
},
459+
ClusterIP: "None",
460+
},
461+
},
462+
},
463+
},
464+
{
465+
name: "expired sandbox",
466+
// Input sandbox spec
467+
sandboxSpec: sandboxv1alpha1.SandboxSpec{
468+
ShutdownTime: ptr.To(metav1.NewTime(time.Now().Add(-10 * time.Second))),
469+
PodTemplate: sandboxv1alpha1.PodTemplate{
470+
Spec: corev1.PodSpec{
471+
Containers: []corev1.Container{
472+
{
473+
Name: "test-container",
474+
},
475+
},
476+
},
477+
},
478+
},
479+
// Verify Sandbox status
480+
wantStatus: sandboxv1alpha1.SandboxStatus{
481+
Phase: sandboxv1alpha1.SandboxTerminating,
482+
Replicas: 0,
483+
LabelSelector: "",
484+
Conditions: []metav1.Condition{
485+
{
486+
Type: "Ready",
487+
Status: "False",
488+
ObservedGeneration: 1,
489+
Reason: "SandboxExpired",
490+
Message: "Sandbox has expired",
491+
},
492+
},
493+
},
494+
wantObjs: []client.Object{},
495+
},
409496
}
410497

411498
for _, tc := range testCases {

0 commit comments

Comments
 (0)