Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ It follows the same release cycle as other containers, so the latest release is
You will need to setup the environment variable `CSI_ENDPOINT` for the mock driver to know where to create the unix
domain socket.

For more complicated test-cases see [how to use JavaScript hooks from the driver](hooks-howto.md).

## For CSI Driver Tests

To test drivers please take a look at [pkg/sanity](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity).
Expand Down
30 changes: 30 additions & 0 deletions cmd/mock-driver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main
import (
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"os/signal"
Expand All @@ -26,17 +27,20 @@ import (

"github.com/kubernetes-csi/csi-test/v3/driver"
"github.com/kubernetes-csi/csi-test/v3/mock/service"
"gopkg.in/yaml.v2"
)

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

endpoint := os.Getenv("CSI_ENDPOINT")
Expand All @@ -46,6 +50,15 @@ func main() {
controllerEndpoint = endpoint
}

if hooksFile != "" {
execHooks, err := parseHooksFile(hooksFile)
if err == nil {
config.ExecHooks = execHooks
} else {
fmt.Printf("Failed to load hooks file %s: %v", hooksFile, err)
}
}

// Create mock driver
s := service.New(config)

Expand Down Expand Up @@ -198,3 +211,20 @@ func listen(endpoint string) (net.Listener, func(), error) {
l, err := net.Listen(proto, addr)
return l, cleanup, err
}

func parseHooksFile(file string) (*service.Hooks, error) {
var hooks service.Hooks

fr, err := os.Open(file)
if err != nil {
return nil, err
}
defer fr.Close()
bytes, _ := ioutil.ReadAll(fr)
err = yaml.UnmarshalStrict([]byte(bytes), &hooks)
if err != nil {
return nil, err
}
fmt.Printf("Hooks file %s loaded\n", file)
return &hooks, err
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ require (
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/onsi/ginkgo v1.10.3
github.com/onsi/gomega v1.7.1
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
github.com/sirupsen/logrus v1.4.2
golang.org/x/net v0.0.0-20191112182307-2180aed22343
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/genproto v0.0.0-20191114150713-6bbd007550de // indirect
google.golang.org/grpc v1.25.1
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/yaml.v2 v2.2.5
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down Expand Up @@ -86,6 +88,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
72 changes: 72 additions & 0 deletions hooks-howto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# JavaScript Hooks in the CSI Mock Driver
The CSI mock driver can call JavaScript hooks during the execution of the CSI
method calls. These hooks can be configured in an external YAML file that can be
passed to the mock driver sidecar container as a `ConfigMap` volume.

## Example
Here's an usage example of the feature. First, prepare a YAML file defining
some JavaScript hooks. Let's call it `hooks.yaml`:

```javascript
globals: |
count = 0;
console.log("Globals loaded, count set to " + count);
createVolumeStart: |
count = count + 1;
console.log("CreateVolumeStart: The value of count is " + count);
if (count > 2) { OK; } else { DEADLINEEXCEEDED; };
createVolumeEnd: |
console.log("CreateVolumeEnd");
```

Create a `ConfigMap` from the YAML:

```sh
kubectl create configmap hooks-config --from-file hooks.yaml
```
Configure the CSI mock driver to use it -- these are the relevant parts of the
sidecar definition YAMLs:

```yaml
...
containers:
...
- name: csi-mock-plugin
...
args:
- --hooks-file=/etc/hooks/hooks.yaml
...
volumeMounts:
...
- name: hooks-volume
mountPath: /etc/hooks
...
volumes:
- name: hooks-volume
configMap:
name: hooks-config
...
```

Now the driver finds the hooks definitions file and creates a JavaScript VM.
Just one instance of the VM exists through the life of the driver. It executes
the pieces of code as per the YAML file. One special case is the `globals` hook
that is executed right after loading the file and it's intended for variable
initialization, common function definitions, etc.

Each code snippet is executed at given place in the code: in this example
`createVolumeStart` at the beginning of the `CreateVolume` method in the driver.
The result of the hook snipped is evaluated: it would be the value of the last
expression executed. If the result is an integer value it gets interpreted as
gRPC code and in case it's non-zero (not `OK`), the CSI driver method would
return this as its response error. The complete list of the gRPC constants is
defined in the [hooks-const.go](./mock/service/hooks-const.go) file.

In the example: The variable `count` was initialized to zero in the `globals`
hook. Each time the `CreateVolume` method is called the hook is executed so
`count` is increased by one (it's always the same variable) and for the first
two calls the last expression of the code snipped is `DEADLINEEXCEEDED` which
causes the `CreateVolume` method to fail with the given code. Subsequent calls
would return `0` so things would work normally. Also -- the `console.out()`
allows for logging to stdout so the messages from the hooks appear among the
output from the driver itself.
Loading