Skip to content

Commit 050e6f4

Browse files
committed
Add experimental javascript hooks
1 parent 3ec4a00 commit 050e6f4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+29615
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ It follows the same release cycle as other containers, so the latest release is
2020
You will need to setup the environment variable `CSI_ENDPOINT` for the mock driver to know where to create the unix
2121
domain socket.
2222

23+
For more complicated test-cases see [how to use JavaScript hooks from the driver](hooks-howto.md).
24+
2325
## For CSI Driver Tests
2426

2527
To test drivers please take a look at [pkg/sanity](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity).

cmd/mock-driver/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818
import (
1919
"flag"
2020
"fmt"
21+
"io/ioutil"
2122
"net"
2223
"os"
2324
"os/signal"
@@ -26,17 +27,20 @@ import (
2627

2728
"github.com/kubernetes-csi/csi-test/v3/driver"
2829
"github.com/kubernetes-csi/csi-test/v3/mock/service"
30+
"gopkg.in/yaml.v2"
2931
)
3032

3133
func main() {
3234
var config service.Config
35+
var hooksFile string = ""
3336
flag.BoolVar(&config.DisableAttach, "disable-attach", false, "Disables RPC_PUBLISH_UNPUBLISH_VOLUME capability.")
3437
flag.StringVar(&config.DriverName, "name", service.Name, "CSI driver name.")
3538
flag.Int64Var(&config.AttachLimit, "attach-limit", 2, "number of attachable volumes on a node")
3639
flag.BoolVar(&config.NodeExpansionRequired, "node-expand-required", false, "Enables NodeServiceCapability_RPC_EXPAND_VOLUME capacity.")
3740
flag.BoolVar(&config.DisableControllerExpansion, "disable-controller-expansion", false, "Disables ControllerServiceCapability_RPC_EXPAND_VOLUME capability.")
3841
flag.BoolVar(&config.DisableOnlineExpansion, "disable-online-expansion", false, "Disables online volume expansion capability.")
3942
flag.BoolVar(&config.PermissiveTargetPath, "permissive-target-path", false, "Allows the CO to create PublishVolumeRequest.TargetPath, which violates the CSI spec.")
43+
flag.StringVar(&hooksFile, "hooks-file", "", "YAML file with hook scripts.")
4044
flag.Parse()
4145

4246
endpoint := os.Getenv("CSI_ENDPOINT")
@@ -46,6 +50,15 @@ func main() {
4650
controllerEndpoint = endpoint
4751
}
4852

53+
if hooksFile != "" {
54+
execHooks, err := parseHooksFile(hooksFile)
55+
if err == nil {
56+
config.ExecHooks = execHooks
57+
} else {
58+
fmt.Printf("Failed to load hooks file %s: %v", hooksFile, err)
59+
}
60+
}
61+
4962
// Create mock driver
5063
s := service.New(config)
5164

@@ -198,3 +211,20 @@ func listen(endpoint string) (net.Listener, func(), error) {
198211
l, err := net.Listen(proto, addr)
199212
return l, cleanup, err
200213
}
214+
215+
func parseHooksFile(file string) (*service.Hooks, error) {
216+
var hooks service.Hooks
217+
218+
fr, err := os.Open(file)
219+
if err != nil {
220+
return nil, err
221+
}
222+
defer fr.Close()
223+
bytes, _ := ioutil.ReadAll(fr)
224+
err = yaml.UnmarshalStrict([]byte(bytes), &hooks)
225+
if err != nil {
226+
return nil, err
227+
}
228+
fmt.Printf("Hooks file %s loaded\n", file)
229+
return &hooks, err
230+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ require (
1010
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
1111
github.com/onsi/ginkgo v1.10.3
1212
github.com/onsi/gomega v1.7.1
13+
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
1314
github.com/sirupsen/logrus v1.4.2
1415
golang.org/x/net v0.0.0-20191112182307-2180aed22343
1516
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 // indirect
1617
golang.org/x/text v0.3.2 // indirect
1718
google.golang.org/genproto v0.0.0-20191114150713-6bbd007550de // indirect
1819
google.golang.org/grpc v1.25.1
20+
gopkg.in/sourcemap.v1 v1.0.5 // indirect
1921
gopkg.in/yaml.v2 v2.2.5
2022
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
3434
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3535
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
3636
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
37+
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=
38+
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
3739
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
3840
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
3941
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -86,6 +88,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
8688
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8789
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
8890
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
91+
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
92+
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
8993
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
9094
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
9195
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

hooks-howto.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# JavaScript Hooks in the CSI Mock Driver
2+
The CSI mock driver can call JavaScript hooks during the execution of the CSI
3+
method calls. These hooks can be configured in an external YAML file that can be
4+
passed to the mock driver sidecar container as a `ConfigMap` volume.
5+
6+
## Example
7+
Here's an usage example of the feature. First, prepare a YAML file defining
8+
some JavaScript hooks. Let's call it `hooks.yaml`:
9+
10+
```javascript
11+
globals: |
12+
count = 0;
13+
console.log("Globals loaded, count set to " + count);
14+
createVolumeStart: |
15+
count = count + 1;
16+
console.log("CreateVolumeStart: The value of count is " + count);
17+
if (count > 2) { OK; } else { DEADLINEEXCEEDED; };
18+
createVolumeEnd: |
19+
console.log("CreateVolumeEnd");
20+
```
21+
22+
Create a `ConfigMap` from the YAML:
23+
24+
```sh
25+
kubectl create configmap hooks-config --from-file hooks.yaml
26+
```
27+
Configure the CSI mock driver to use it -- these are the relevant parts of the
28+
sidecar definition YAMLs:
29+
30+
```yaml
31+
...
32+
containers:
33+
...
34+
- name: csi-mock-plugin
35+
...
36+
args:
37+
- --hooks-file=/etc/hooks/hooks.yaml
38+
...
39+
volumeMounts:
40+
...
41+
- name: hooks-volume
42+
mountPath: /etc/hooks
43+
...
44+
volumes:
45+
- name: hooks-volume
46+
configMap:
47+
name: hooks-config
48+
...
49+
```
50+
51+
Now the driver finds the hooks definitions file and creates a JavaScript VM.
52+
Just one instance of the VM exists through the life of the driver. It executes
53+
the pieces of code as per the YAML file. One special case is the `globals` hook
54+
that is executed right after loading the file and it's intended for variable
55+
initialization, common function definitions, etc.
56+
57+
Each code snippet is executed at given place in the code: in this example
58+
`createVolumeStart` at the beginning of the `CreateVolume` method in the driver.
59+
The result of the hook snipped is evaluated: it would be the value of the last
60+
expression executed. If the result is an integer value it gets interpreted as
61+
gRPC code and in case it's non-zero (not `OK`), the CSI driver method would
62+
return this as its response error. The complete list of the gRPC constants is
63+
defined in the [hooks-const.go](./mock/service/hooks-const.go) file.
64+
65+
In the example: The variable `count` was initialized to zero in the `globals`
66+
hook. Each time the `CreateVolume` method is called the hook is executed so
67+
`count` is increased by one (it's always the same variable) and for the first
68+
two calls the last expression of the code snipped is `DEADLINEEXCEEDED` which
69+
causes the `CreateVolume` method to fail with the given code. Subsequent calls
70+
would return `0` so things would work normally. Also -- the `console.out()`
71+
allows for logging to stdout so the messages from the hooks appear among the
72+
output from the driver itself.

0 commit comments

Comments
 (0)