Skip to content

Commit 634cc33

Browse files
authored
Merge pull request #6814 from dekaihu/interpreter-notebook
add interpreter-notebook
2 parents 0fde1d2 + dcc2735 commit 634cc33

File tree

5 files changed

+240
-0
lines changed

5 files changed

+240
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
apiVersion: config.karmada.io/v1alpha1
2+
kind: ResourceInterpreterCustomization
3+
metadata:
4+
name: declarative-configuration-notebook
5+
spec:
6+
target:
7+
apiVersion: kubeflow.org/v1
8+
kind: Notebook
9+
customizations:
10+
replicaResource:
11+
luaScript: >
12+
local kube = require("kube")
13+
function GetReplicas(obj)
14+
local replica = 1
15+
local requirement = kube.accuratePodRequirements(obj.spec.template)
16+
return replica, requirement
17+
end
18+
healthInterpretation:
19+
luaScript: >
20+
function InterpretHealth(observedObj)
21+
if observedObj.status == nil or observedObj.status.containerState == nil then
22+
return false
23+
end
24+
25+
local state = observedObj.status.containerState
26+
if state.running ~= nil then
27+
return true
28+
end
29+
30+
if state.waiting ~= nil then
31+
local reason = state.waiting.reason or ""
32+
if reason == "ContainerCreating" then
33+
return true
34+
end
35+
return false
36+
end
37+
38+
if state.terminated ~= nil then
39+
local reason = state.terminated.reason or ""
40+
local exitCode = state.terminated.exitCode or 0
41+
42+
if reason == "Error" or reason == "OOMKilled" or reason == "ContainerCannotRun" or exitCode ~= 0 then
43+
return false
44+
end
45+
46+
return true
47+
end
48+
49+
return false
50+
end
51+
statusAggregation:
52+
luaScript: >
53+
function AggregateStatus(desiredObj, statusItems)
54+
if statusItems == nil then
55+
return desiredObj
56+
end
57+
if desiredObj.status == nil then desiredObj.status = {} end
58+
59+
if #statusItems == 1 then
60+
desiredObj.status = statusItems[1].status
61+
return desiredObj
62+
end
63+
64+
local status = {
65+
readyReplicas = 0,
66+
containerState = {},
67+
conditions = {}
68+
}
69+
local aggregatedConditions = {}
70+
local successfulClustersNum = 0
71+
local failedClusters = {}
72+
local aggregatedContainerState = nil
73+
local latestStartTime = nil
74+
75+
for i = 1, #statusItems do
76+
local s = statusItems[i]
77+
if s ~= nil and s.status ~= nil then
78+
local st = s.status
79+
status.readyReplicas = status.readyReplicas + (st.readyReplicas or 0)
80+
local cs = st.containerState
81+
82+
local isFailed = cs == nil or (type(cs) == "table" and next(cs) == nil) or cs.terminated ~= nil or cs.waiting ~= nil
83+
if isFailed then
84+
table.insert(failedClusters, s.clusterName)
85+
if cs == nil or next(cs) == nil then
86+
aggregatedContainerState ={ waiting = { reason = "Unschedulable" } }
87+
else
88+
aggregatedContainerState = cs
89+
end
90+
else
91+
if cs.running ~= nil and #failedClusters == 0 then
92+
successfulClustersNum = successfulClustersNum + 1
93+
local startedAt = cs.running.startedAt
94+
if aggregatedContainerState == nil then
95+
aggregatedContainerState = { running = { startedAt = startedAt } }
96+
latestStartTime = startedAt
97+
else
98+
if startedAt ~= nil and (latestStartTime == nil or startedAt > latestStartTime) then
99+
latestStartTime = startedAt
100+
aggregatedContainerState.running = { startedAt = startedAt }
101+
end
102+
end
103+
end
104+
end
105+
end
106+
end
107+
108+
if #failedClusters > 0 then
109+
table.insert(aggregatedConditions, {
110+
type = "Failed",
111+
status = "True",
112+
lastProbeTime = os.date("!%Y-%m-%dT%H:%M:%SZ"),
113+
lastTransitionTime = os.date("!%Y-%m-%dT%H:%M:%SZ"),
114+
reason = "NotebookFailed",
115+
message = "Notebook executed failed in member clusters: " .. table.concat(failedClusters, ", ")
116+
})
117+
end
118+
119+
if successfulClustersNum == #statusItems and successfulClustersNum > 0 then
120+
table.insert(aggregatedConditions, {
121+
type = "Ready",
122+
status = "True",
123+
lastProbeTime = os.date("!%Y-%m-%dT%H:%M:%SZ"),
124+
lastTransitionTime = os.date("!%Y-%m-%dT%H:%M:%SZ"),
125+
reason = "Ready",
126+
message = "All notebooks are ready"
127+
})
128+
end
129+
130+
status.conditions = aggregatedConditions
131+
status.containerState = aggregatedContainerState
132+
desiredObj.status = status
133+
return desiredObj
134+
end
135+
statusReflection:
136+
luaScript: >
137+
function ReflectStatus(observedObj)
138+
if observedObj.status == nil then
139+
return {}
140+
end
141+
local status = {
142+
readyReplicas = 0,
143+
containerState = {},
144+
conditions = {}
145+
}
146+
147+
local s = observedObj.status
148+
status.readyReplicas = s.readyReplicas or 0
149+
status.containerState = s.containerState or {}
150+
if type(s.conditions) == "table" then
151+
status.conditions = s.conditions
152+
end
153+
154+
return status
155+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests:
2+
- desiredInputPath: testdata/desired-notebook.yaml
3+
statusInputPath: testdata/status-file.yaml
4+
operation: AggregateStatus
5+
- observedInputPath: testdata/observed-notebook.yaml
6+
operation: InterpretHealth
7+
- observedInputPath: testdata/observed-notebook.yaml
8+
operation: InterpretStatus
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: kubeflow.org/v1
2+
kind: Notebook
3+
metadata:
4+
name: notebook-sample-v1
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: notebook-sample-v1
10+
image: ghcr.io/kubeflow/kubeflow/notebook-servers/jupyter:latest
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
apiVersion: kubeflow.org/v1
2+
kind: Notebook
3+
metadata:
4+
name: notebook-sample-v1
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: notebook-sample-v1
10+
image: ghcr.io/kubeflow/kubeflow/notebook-servers/jupyter:latest
11+
status:
12+
conditions:
13+
- lastProbeTime: "2025-10-09T06:58:59Z"
14+
lastTransitionTime: "2025-10-09T06:58:54Z"
15+
status: "True"
16+
type: Initialized
17+
- lastProbeTime: "2025-10-09T06:58:59Z"
18+
lastTransitionTime: "2025-10-09T06:58:59Z"
19+
status: "True"
20+
type: Ready
21+
- lastProbeTime: "2025-10-09T06:58:59Z"
22+
lastTransitionTime: "2025-10-09T06:58:59Z"
23+
status: "True"
24+
type: ContainersReady
25+
- lastProbeTime: "2025-10-09T06:58:59Z"
26+
lastTransitionTime: "2025-10-09T06:58:54Z"
27+
status: "True"
28+
type: PodScheduled
29+
containerState:
30+
running:
31+
startedAt: "2025-10-09T06:58:58Z"
32+
readyReplicas: 1
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
status:
2+
conditions:
3+
- lastProbeTime: "2025-10-09T06:58:59Z"
4+
lastTransitionTime: "2025-10-09T06:58:54Z"
5+
status: "True"
6+
type: Initialized
7+
- lastProbeTime: "2025-10-09T06:58:59Z"
8+
lastTransitionTime: "2025-10-09T06:58:59Z"
9+
status: "True"
10+
type: Ready
11+
- lastProbeTime: "2025-10-09T06:58:59Z"
12+
lastTransitionTime: "2025-10-09T06:58:59Z"
13+
status: "True"
14+
type: ContainersReady
15+
- lastProbeTime: "2025-10-09T06:58:59Z"
16+
lastTransitionTime: "2025-10-09T06:58:54Z"
17+
status: "True"
18+
type: PodScheduled
19+
containerState:
20+
running:
21+
startedAt: "2025-10-09T06:58:58Z"
22+
readyReplicas: 1
23+
---
24+
status:
25+
conditions:
26+
- lastProbeTime: "2025-10-24T07:56:35Z"
27+
lastTransitionTime: "2025-10-24T07:56:35Z"
28+
message: '0/6 nodes are available: 1 node(s) had untolerated taint {virtual-kubelet.io/provider:
29+
leinao}, 5 node(s) were unschedulable. preemption: 0/6 nodes are available:
30+
6 Preemption is not helpful for scheduling.'
31+
reason: Unschedulable
32+
status: "False"
33+
type: PodScheduled
34+
containerState: {}
35+
readyReplicas: 0

0 commit comments

Comments
 (0)