Skip to content

Commit d04084d

Browse files
kazukousensanposhiho
authored andcommitted
Support permit plugin
1 parent 06c9f99 commit d04084d

File tree

22 files changed

+369
-12
lines changed

22 files changed

+369
-12
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ examples/advanced/main.wasm: examples/advanced/main.go
1010

1111
.PHONY: build-tinygo
1212
build-tinygo: examples/nodenumber/main.wasm examples/advanced/main.wasm guest/testdata/cyclestate/main.wasm guest/testdata/filter/main.wasm guest/testdata/score/main.wasm \
13-
guest/testdata/bind/main.wasm guest/testdata/reserve/main.wasm guest/testdata/handle/main.wasm
13+
guest/testdata/bind/main.wasm guest/testdata/reserve/main.wasm guest/testdata/handle/main.wasm guest/testdata/permit/main.wasm
1414

1515
%/main-debug.wasm: %/main.go
1616
@(cd $(@D); tinygo build -o main-debug.wasm -gc=custom -tags=custommalloc -scheduler=none -target=wasi .)

guest/api/types.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
package api
1818

19-
import "sigs.k8s.io/kube-scheduler-wasm-extension/guest/api/proto"
19+
import (
20+
"time"
21+
22+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api/proto"
23+
)
2024

2125
// CycleState is a WebAssembly implementation of framework.CycleState.
2226
//
@@ -122,6 +126,13 @@ type ReservePlugin interface {
122126
Unreserve(state CycleState, p proto.Pod, nodeName string)
123127
}
124128

129+
// PermitPlugin is a WebAssembly implementation of framework.PermitPlugin.
130+
type PermitPlugin interface {
131+
Plugin
132+
133+
Permit(state CycleState, p proto.Pod, nodeName string) (*Status, time.Duration)
134+
}
135+
125136
// PreBindPlugin is a WebAssembly implementation of framework.PreBindPlugin.
126137
type PreBindPlugin interface {
127138
Plugin

guest/internal/mem/mem.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ func BytesToPtr(b []byte) (uint32, uint32) {
5353
return uint32(uintptr(ptr)), uint32(len(b))
5454
}
5555

56+
// Int64ToPtr returns a pointer for the given int64 number in a way compatible
57+
// with WebAssembly numeric types.
58+
// The returned pointer aliases the number hence it must be kept alive until ptr
59+
// is no longer needed.
60+
func Int64ToPtr(n int64) uint32 {
61+
ptr := unsafe.Pointer(&n)
62+
return uint32(uintptr(ptr))
63+
}
64+
5665
// Update is for decoding values from memory. The updater doesn't keep a
5766
// reference to the underlying bytes, so we don't need to copy them.
5867
func Update(

guest/permit/imports.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//go:build tinygo.wasm
2+
3+
package permit
4+
5+
//go:wasmimport k8s.io/scheduler result.timeout
6+
func setTimeoutResult(uint32)

guest/permit/imports_stub.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//go:build !tinygo.wasm
2+
3+
package permit
4+
5+
// setTimeoutResult is stubbed for compilation outside TinyGo.
6+
func setTimeoutResult(uint32) {}

guest/permit/permit.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package permit exports an api.PermitPlugin to the host.
18+
package permit
19+
20+
import (
21+
"runtime"
22+
23+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api"
24+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/internal/cyclestate"
25+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/internal/imports"
26+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/internal/mem"
27+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/internal/plugin"
28+
)
29+
30+
// permit is the current plugin assigned with SetPlugin.
31+
var permit api.PermitPlugin
32+
33+
// SetPlugin should be called in `main` to assign an api.PermitPlugin
34+
// instance.
35+
//
36+
// For example:
37+
//
38+
// func main() {
39+
// plugin := permitPlugin{}
40+
// permit.SetPlugin(plugin)
41+
// }
42+
//
43+
// type permitPlugin struct{}
44+
//
45+
// func (permitPlugin) Permit(state api.CycleState, p proto.Pod, nodeName string) (status *api.Status, timeout time.Duration)
46+
// // Write state you need on Permit
47+
// }
48+
func SetPlugin(permitPlugin api.PermitPlugin) {
49+
if permitPlugin == nil {
50+
panic("nil permitPlugin")
51+
}
52+
permit = permitPlugin
53+
plugin.MustSet(permit)
54+
}
55+
56+
// prevent unused lint errors (lint is run with normal go).
57+
var _ func() uint32 = _permit
58+
59+
// _permit is only exported to the host.
60+
//
61+
//export permit
62+
func _permit() uint32 {
63+
if permit == nil { // Then, the user didn't define one.
64+
// Unlike most plugins we always export permit so that we can reset
65+
// the cycle state: return success to avoid no-op overhead.
66+
return 0
67+
}
68+
69+
pod := cyclestate.Pod
70+
nodeName := imports.NodeName()
71+
status, timeout := permit.Permit(cyclestate.Values, pod, nodeName)
72+
73+
ptr := mem.Int64ToPtr(int64(timeout))
74+
setTimeoutResult(ptr)
75+
runtime.KeepAlive(timeout) // untir ptr is no longer needed.
76+
77+
return imports.StatusToCode(status)
78+
}

guest/plugin/plugin.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/enqueue"
2323
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/filter"
2424
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/internal/prefilter"
25+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/permit"
2526
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/postbind"
2627
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/postfilter"
2728
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/prebind"
@@ -72,6 +73,9 @@ func Set(plugin api.Plugin) {
7273
if plugin, ok := plugin.(api.ReservePlugin); ok {
7374
reserve.SetPlugin(plugin)
7475
}
76+
if plugin, ok := plugin.(api.PermitPlugin); ok {
77+
permit.SetPlugin(plugin)
78+
}
7579
if plugin, ok := plugin.(api.PreBindPlugin); ok {
7680
prebind.SetPlugin(plugin)
7781
}

guest/testdata/cyclestate/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ package main
2020

2121
import (
2222
"os"
23+
"time"
2324
"unsafe"
2425

2526
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api"
2627
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api/proto"
2728
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/bind"
2829
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/enqueue"
2930
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/filter"
31+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/permit"
3032
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/postbind"
3133
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/postfilter"
3234
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/prebind"
@@ -67,6 +69,7 @@ func main() {
6769
score.SetPlugin(plugin)
6870
scoreextensions.SetPlugin(plugin)
6971
reserve.SetPlugin(plugin)
72+
permit.SetPlugin(plugin)
7073
prebind.SetPlugin(plugin)
7174
bind.SetPlugin(plugin)
7275
postbind.SetPlugin(plugin)
@@ -187,6 +190,11 @@ func (statePlugin) Unreserve(state api.CycleState, pod proto.Pod, nodeName strin
187190
mustFilterState(state)
188191
}
189192

193+
func (statePlugin) Permit(state api.CycleState, pod proto.Pod, nodeName string) (status *api.Status, timeout time.Duration) {
194+
mustFilterState(state)
195+
return
196+
}
197+
190198
func (statePlugin) PreBind(state api.CycleState, pod proto.Pod, _ string) (status *api.Status) {
191199
if unsafe.Pointer(pod.Spec()) != unsafe.Pointer(podSpec) {
192200
panic("didn't cache pod from pre-filter")
10.1 KB
Binary file not shown.

guest/testdata/permit/main.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"time"
21+
22+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api"
23+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/api/proto"
24+
"sigs.k8s.io/kube-scheduler-wasm-extension/guest/permit"
25+
)
26+
27+
type extensionPoints interface {
28+
api.PermitPlugin
29+
}
30+
31+
func main() {
32+
var plugin extensionPoints = permitPlugin{}
33+
permit.SetPlugin(plugin)
34+
}
35+
36+
type permitPlugin struct{}
37+
38+
func (permitPlugin) Permit(state api.CycleState, pod proto.Pod, nodeName string) (*api.Status, time.Duration) {
39+
status, timeout := api.StatusCodeSuccess, time.Duration(0)
40+
if nodeName == "bad" {
41+
status = api.StatusCodeError
42+
} else if nodeName == "wait" {
43+
status = api.StatusCodeWait
44+
timeout = 10 * time.Second
45+
}
46+
return &api.Status{Code: status, Reason: "name is " + nodeName}, timeout
47+
}

0 commit comments

Comments
 (0)