commit
8e4c2a9df8
|
|
@ -1,3 +1,10 @@
|
||||||
|
# v1.1.0
|
||||||
|
|
||||||
|
Released 2021-02-21
|
||||||
|
|
||||||
|
- support for csi-v1.3.0
|
||||||
|
- fix a snapshot issue when requested with specific `snapshot_id`
|
||||||
|
|
||||||
# v1.0.1
|
# v1.0.1
|
||||||
|
|
||||||
Released 2021-01-29
|
Released 2021-01-29
|
||||||
|
|
|
||||||
80
README.md
80
README.md
|
|
@ -45,7 +45,17 @@ Predominantly 3 things are needed:
|
||||||
|
|
||||||
You should install/configure the requirements for both nfs and iscsi.
|
You should install/configure the requirements for both nfs and iscsi.
|
||||||
|
|
||||||
Follow the instructions here: https://netapp-trident.readthedocs.io/en/stable-v20.04/kubernetes/operations/tasks/worker.html
|
### nfs
|
||||||
|
|
||||||
|
```
|
||||||
|
RHEL / CentOS
|
||||||
|
sudo yum install -y nfs-utils
|
||||||
|
|
||||||
|
Ubuntu / Debian
|
||||||
|
sudo apt-get install -y nfs-common
|
||||||
|
```
|
||||||
|
|
||||||
|
### iscsi
|
||||||
|
|
||||||
Note that `multipath` is supported for the `iscsi`-based drivers. Simply setup
|
Note that `multipath` is supported for the `iscsi`-based drivers. Simply setup
|
||||||
multipath to your liking and set multiple portals in the config as appropriate.
|
multipath to your liking and set multiple portals in the config as appropriate.
|
||||||
|
|
@ -54,10 +64,51 @@ If you are running Kubernetes with rancher/rke please see the following:
|
||||||
|
|
||||||
- https://github.com/rancher/rke/issues/1846
|
- https://github.com/rancher/rke/issues/1846
|
||||||
|
|
||||||
|
```
|
||||||
|
RHEL / CentOS
|
||||||
|
|
||||||
|
# Install the following system packages
|
||||||
|
sudo yum install -y lsscsi iscsi-initiator-utils sg3_utils device-mapper-multipath
|
||||||
|
|
||||||
|
# Enable multipathing
|
||||||
|
sudo mpathconf --enable --with_multipathd y
|
||||||
|
|
||||||
|
# Ensure that iscsid and multipathd are running
|
||||||
|
sudo systemctl enable iscsid multipathd
|
||||||
|
sudo systemctl start iscsid multipathd
|
||||||
|
|
||||||
|
# Start and enable iscsi
|
||||||
|
sudo systemctl enable iscsi
|
||||||
|
sudo systemctl start iscsi
|
||||||
|
|
||||||
|
|
||||||
|
Ubuntu / Debian
|
||||||
|
|
||||||
|
# Install the following system packages
|
||||||
|
sudo apt-get install -y open-iscsi lsscsi sg3-utils multipath-tools scsitools
|
||||||
|
|
||||||
|
# Enable multipathing
|
||||||
|
sudo tee /etc/multipath.conf <<-'EOF'
|
||||||
|
defaults {
|
||||||
|
user_friendly_names yes
|
||||||
|
find_multipaths yes
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl enable multipath-tools.service
|
||||||
|
sudo service multipath-tools restart
|
||||||
|
|
||||||
|
# Ensure that open-iscsi and multipath-tools are enabled and running
|
||||||
|
sudo systemctl status multipath-tools
|
||||||
|
sudo systemctl enable open-iscsi.service
|
||||||
|
sudo service open-iscsi start
|
||||||
|
sudo systemctl status open-iscsi
|
||||||
|
```
|
||||||
|
|
||||||
### freenas-smb
|
### freenas-smb
|
||||||
|
|
||||||
If using with Windows based machines you may need to enable guest access (even
|
If using with Windows based machines you may need to enable guest access (even
|
||||||
if you are connecting with credentiasl)
|
if you are connecting with credentials)
|
||||||
|
|
||||||
```
|
```
|
||||||
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters AllowInsecureGuestAuth -Value 1
|
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters AllowInsecureGuestAuth -Value 1
|
||||||
|
|
@ -81,7 +132,7 @@ Server preparation depends slightly on which `driver` you are using.
|
||||||
|
|
||||||
### FreeNAS (freenas-nfs, freenas-iscsi, freenas-smb)
|
### FreeNAS (freenas-nfs, freenas-iscsi, freenas-smb)
|
||||||
|
|
||||||
The recommended version of FreeNAS is 11.3+, however the driver should work
|
The recommended version of FreeNAS is 12.0-U2+, however the driver should work
|
||||||
with much older versions as well.
|
with much older versions as well.
|
||||||
|
|
||||||
Ensure the following services are configurged and running:
|
Ensure the following services are configurged and running:
|
||||||
|
|
@ -90,12 +141,20 @@ Ensure the following services are configurged and running:
|
||||||
- ensure `zsh`, `bash`, or `sh` is set as the root shell, `csh` gives false errors due to quoting
|
- ensure `zsh`, `bash`, or `sh` is set as the root shell, `csh` gives false errors due to quoting
|
||||||
- nfs
|
- nfs
|
||||||
- iscsi
|
- iscsi
|
||||||
- when using the FreeNAS API concurrently the `/etc/ctl.conf` file on the
|
- (fixed in 12.0-U2+) when using the FreeNAS API concurrently the
|
||||||
server can become invalid, some sample scripts are provided in the
|
`/etc/ctl.conf` file on the server can become invalid, some sample scripts
|
||||||
`contrib` directory to clean things up
|
are provided in the `contrib` directory to clean things up ie: copy the
|
||||||
ie: copy the script to the server and directly and run - `./ctld-config-watchdog-db.sh | logger -t ctld-config-watchdog-db.sh &`
|
script to the server and directly and run - `./ctld-config-watchdog-db.sh | logger -t ctld-config-watchdog-db.sh &`
|
||||||
please read the scripts and set the variables as appropriate for your server.
|
please read the scripts and set the variables as appropriate for your server.
|
||||||
- ensure you have pre-emptively created portal, group, auth
|
- ensure you have pre-emptively created portals, initatior groups, auths
|
||||||
|
- make note of the respective IDs (the true ID may not reflect what is
|
||||||
|
visible in the UI)
|
||||||
|
- IDs can be visible by clicking the the `Edit` link and finding the ID in the
|
||||||
|
browser address bar
|
||||||
|
- Optionally you may use the following to retrieve appropiate IDs:
|
||||||
|
- `curl --header "Accept: application/json" --user root:<password> 'http(s)://<ip>/api/v2.0/iscsi/portal'`
|
||||||
|
- `curl --header "Accept: application/json" --user root:<password> 'http(s)://<ip>/api/v2.0/iscsi/initiator'`
|
||||||
|
- `curl --header "Accept: application/json" --user root:<password> 'http(s)://<ip>/api/v2.0/iscsi/auth'`
|
||||||
- smb
|
- smb
|
||||||
|
|
||||||
In addition, if you want to use a non-root user for the ssh operations you may
|
In addition, if you want to use a non-root user for the ssh operations you may
|
||||||
|
|
@ -223,6 +282,11 @@ Install `democratic-csi` as usual with `volumeSnapshotClasses` defined as approp
|
||||||
- https://kubernetes.io/docs/concepts/storage/volume-snapshots/
|
- https://kubernetes.io/docs/concepts/storage/volume-snapshots/
|
||||||
- https://github.com/kubernetes-csi/external-snapshotter#usage
|
- https://github.com/kubernetes-csi/external-snapshotter#usage
|
||||||
|
|
||||||
|
# Sponsors
|
||||||
|
|
||||||
|
A special shout out to the wonderful sponsors of the project!
|
||||||
|
|
||||||
|
[](http://ixsystems.com/)
|
||||||
# Related
|
# Related
|
||||||
|
|
||||||
- https://github.com/nmaupu/freenas-provisioner
|
- https://github.com/nmaupu/freenas-provisioner
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,8 @@ const GeneralUtils = require("../src/utils/general");
|
||||||
if (args.logLevel) {
|
if (args.logLevel) {
|
||||||
logger.level = args.logLevel;
|
logger.level = args.logLevel;
|
||||||
}
|
}
|
||||||
const csiVersion = process.env.CSI_VERSION || "1.2.0";
|
|
||||||
|
const csiVersion = process.env.CSI_VERSION || args.csiVersion || "1.2.0";
|
||||||
const PROTO_PATH = __dirname + "/../csi_proto/csi-v" + csiVersion + ".proto";
|
const PROTO_PATH = __dirname + "/../csi_proto/csi-v" + csiVersion + ".proto";
|
||||||
|
|
||||||
// Suggested options for similarity to existing grpc.load behavior
|
// Suggested options for similarity to existing grpc.load behavior
|
||||||
|
|
@ -101,7 +102,7 @@ logger.info("initializing csi driver: %s", options.driver);
|
||||||
let driver;
|
let driver;
|
||||||
try {
|
try {
|
||||||
driver = require("../src/driver/factory").factory(
|
driver = require("../src/driver/factory").factory(
|
||||||
{ logger, args, cache, package },
|
{ logger, args, cache, package, csiVersion },
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -239,6 +240,9 @@ function getServer() {
|
||||||
async ValidateVolumeCapabilities(call, callback) {
|
async ValidateVolumeCapabilities(call, callback) {
|
||||||
requestHandlerProxy(call, callback, arguments.callee.name);
|
requestHandlerProxy(call, callback, arguments.callee.name);
|
||||||
},
|
},
|
||||||
|
async ControllerGetVolume(call, callback) {
|
||||||
|
requestHandlerProxy(call, callback, arguments.callee.name);
|
||||||
|
},
|
||||||
async ListVolumes(call, callback) {
|
async ListVolumes(call, callback) {
|
||||||
requestHandlerProxy(call, callback, arguments.callee.name);
|
requestHandlerProxy(call, callback, arguments.callee.name);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ const fs = require("fs");
|
||||||
|
|
||||||
let options;
|
let options;
|
||||||
const args = require("yargs")
|
const args = require("yargs")
|
||||||
.env("DEMOCRATIC_CSI")
|
.env("DEMOCRATIC_CSI_LIVENESS_PROBE")
|
||||||
.scriptName("democratic-csi")
|
.scriptName("liveness-probe")
|
||||||
.usage("$0 [options]")
|
.usage("$0 [options]")
|
||||||
.option("csi-version", {
|
.option("csi-version", {
|
||||||
describe: "versin of the csi spec to load",
|
describe: "versin of the csi spec to load",
|
||||||
choices: ["0.2.0", "0.3.0", "1.0.0", "1.1.0", "1.2.0"],
|
choices: ["0.2.0", "0.3.0", "1.0.0", "1.1.0", "1.2.0", "1.3.0"],
|
||||||
})
|
})
|
||||||
.demandOption(["csi-version"], "csi-version is required")
|
.demandOption(["csi-version"], "csi-version is required")
|
||||||
.option("csi-address", {
|
.option("csi-address", {
|
||||||
|
|
@ -27,7 +27,7 @@ args.version = package.version;
|
||||||
//const grpc = require("grpc");
|
//const grpc = require("grpc");
|
||||||
const grpc = require("grpc-uds");
|
const grpc = require("grpc-uds");
|
||||||
const protoLoader = require("@grpc/proto-loader");
|
const protoLoader = require("@grpc/proto-loader");
|
||||||
const csiVersion = process.env.CSI_VERSION || "1.1.0";
|
const csiVersion = process.env.CSI_VERSION || args.csiVersion || "1.2.0";
|
||||||
const PROTO_PATH = __dirname + "/../csi_proto/csi-v" + csiVersion + ".proto";
|
const PROTO_PATH = __dirname + "/../csi_proto/csi-v" + csiVersion + ".proto";
|
||||||
|
|
||||||
// Suggested options for similarity to existing grpc.load behavior
|
// Suggested options for similarity to existing grpc.load behavior
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "democratic-csi",
|
"name": "democratic-csi",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -18,11 +18,11 @@
|
||||||
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
|
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
|
||||||
},
|
},
|
||||||
"@babel/highlight": {
|
"@babel/highlight": {
|
||||||
"version": "7.10.4",
|
"version": "7.12.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
|
||||||
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
|
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-validator-identifier": "^7.10.4",
|
"@babel/helper-validator-identifier": "^7.12.11",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.0.0",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -567,11 +567,11 @@
|
||||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||||
},
|
},
|
||||||
"eslint": {
|
"eslint": {
|
||||||
"version": "7.18.0",
|
"version": "7.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
|
||||||
"integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==",
|
"integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.0.0",
|
"@babel/code-frame": "7.12.11",
|
||||||
"@eslint/eslintrc": "^0.3.0",
|
"@eslint/eslintrc": "^0.3.0",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
|
|
@ -583,7 +583,7 @@
|
||||||
"eslint-utils": "^2.1.0",
|
"eslint-utils": "^2.1.0",
|
||||||
"eslint-visitor-keys": "^2.0.0",
|
"eslint-visitor-keys": "^2.0.0",
|
||||||
"espree": "^7.3.1",
|
"espree": "^7.3.1",
|
||||||
"esquery": "^1.2.0",
|
"esquery": "^1.4.0",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"file-entry-cache": "^6.0.0",
|
"file-entry-cache": "^6.0.0",
|
||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
|
|
@ -681,9 +681,9 @@
|
||||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||||
},
|
},
|
||||||
"esquery": {
|
"esquery": {
|
||||||
"version": "1.3.1",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
||||||
"integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
|
"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"estraverse": "^5.1.0"
|
"estraverse": "^5.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -756,9 +756,9 @@
|
||||||
"integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg=="
|
"integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg=="
|
||||||
},
|
},
|
||||||
"file-entry-cache": {
|
"file-entry-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
"integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==",
|
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"flat-cache": "^3.0.4"
|
"flat-cache": "^3.0.4"
|
||||||
}
|
}
|
||||||
|
|
@ -1279,9 +1279,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlebars": {
|
"handlebars": {
|
||||||
"version": "4.7.6",
|
"version": "4.7.7",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"neo-async": "^2.6.0",
|
"neo-async": "^2.6.0",
|
||||||
|
|
@ -1477,9 +1477,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
"lodash.camelcase": {
|
"lodash.camelcase": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
|
|
@ -2052,9 +2052,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "7.0.3",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz",
|
||||||
"integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==",
|
"integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"json-schema-traverse": "^1.0.0",
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
|
@ -2120,9 +2120,9 @@
|
||||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "3.10.3",
|
"version": "3.12.8",
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.8.tgz",
|
||||||
"integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==",
|
"integrity": "sha512-fvBeuXOsvqjecUtF/l1dwsrrf5y2BCUk9AOJGzGcm6tE7vegku5u/YvqjyDaAGr422PLoLnrxg3EnRvTqsdC1w==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"uri-js": {
|
"uri-js": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "democratic-csi",
|
"name": "democratic-csi",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"description": "kubernetes csi driver framework",
|
"description": "kubernetes csi driver framework",
|
||||||
"main": "bin/democratic-csi",
|
"main": "bin/democratic-csi",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -20,12 +20,13 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/proto-loader": "^0.5.6",
|
"@grpc/proto-loader": "^0.5.6",
|
||||||
"bunyan": "^1.8.15",
|
"bunyan": "^1.8.15",
|
||||||
"eslint": "^7.18.0",
|
"eslint": "^7.20.0",
|
||||||
"grpc-uds": "^0.1.6",
|
"grpc-uds": "^0.1.6",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.7",
|
||||||
"js-yaml": "^4.0.0",
|
"js-yaml": "^4.0.0",
|
||||||
"lru-cache": "^6.0.0",
|
"lru-cache": "^6.0.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
|
"semver": "^7.3.4",
|
||||||
"ssh2": "^0.8.9",
|
"ssh2": "^0.8.9",
|
||||||
"uri-js": "^4.4.1",
|
"uri-js": "^4.4.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
||||||
|
|
||||||
const Handlebars = require("handlebars");
|
const Handlebars = require("handlebars");
|
||||||
const uuidv4 = require("uuid").v4;
|
const uuidv4 = require("uuid").v4;
|
||||||
|
const semver = require("semver");
|
||||||
|
|
||||||
// zfs common properties
|
// zfs common properties
|
||||||
const MANAGED_PROPERTY_NAME = "democratic-csi:managed_resource";
|
const MANAGED_PROPERTY_NAME = "democratic-csi:managed_resource";
|
||||||
|
|
@ -81,6 +82,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
//"UNKNOWN",
|
//"UNKNOWN",
|
||||||
"CREATE_DELETE_VOLUME",
|
"CREATE_DELETE_VOLUME",
|
||||||
//"PUBLISH_UNPUBLISH_VOLUME",
|
//"PUBLISH_UNPUBLISH_VOLUME",
|
||||||
|
//"LIST_VOLUMES_PUBLISHED_NODES",
|
||||||
"LIST_VOLUMES",
|
"LIST_VOLUMES",
|
||||||
"GET_CAPACITY",
|
"GET_CAPACITY",
|
||||||
"CREATE_DELETE_SNAPSHOT",
|
"CREATE_DELETE_SNAPSHOT",
|
||||||
|
|
@ -88,6 +90,8 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
"CLONE_VOLUME",
|
"CLONE_VOLUME",
|
||||||
//"PUBLISH_READONLY",
|
//"PUBLISH_READONLY",
|
||||||
"EXPAND_VOLUME",
|
"EXPAND_VOLUME",
|
||||||
|
//"VOLUME_CONDITION", // added in v1.3.0
|
||||||
|
//"GET_VOLUME", // added in v1.3.0
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +104,8 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
//"UNKNOWN",
|
//"UNKNOWN",
|
||||||
"STAGE_UNSTAGE_VOLUME",
|
"STAGE_UNSTAGE_VOLUME",
|
||||||
"GET_VOLUME_STATS",
|
"GET_VOLUME_STATS",
|
||||||
//"EXPAND_VOLUME"
|
//"EXPAND_VOLUME",
|
||||||
|
//"VOLUME_CONDITION",
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case "volume":
|
case "volume":
|
||||||
|
|
@ -109,6 +114,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
"STAGE_UNSTAGE_VOLUME",
|
"STAGE_UNSTAGE_VOLUME",
|
||||||
"GET_VOLUME_STATS",
|
"GET_VOLUME_STATS",
|
||||||
"EXPAND_VOLUME",
|
"EXPAND_VOLUME",
|
||||||
|
//"VOLUME_CONDITION",
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -257,6 +263,108 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
return { valid, message };
|
return { valid, message };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getVolumeStatus(volume_id) {
|
||||||
|
const driver = this;
|
||||||
|
|
||||||
|
if (!!!semver.satisfies(driver.ctx.csiVersion, ">=1.2.0")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abnormal = false;
|
||||||
|
let message = "OK";
|
||||||
|
let volume_status = {};
|
||||||
|
|
||||||
|
//LIST_VOLUMES_PUBLISHED_NODES
|
||||||
|
if (
|
||||||
|
semver.satisfies(driver.ctx.csiVersion, ">=1.2.0") &&
|
||||||
|
driver.options.service.controller.capabilities.rpc.includes(
|
||||||
|
"LIST_VOLUMES_PUBLISHED_NODES"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// TODO: let drivers fill this in
|
||||||
|
volume_status.published_node_ids = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//VOLUME_CONDITION
|
||||||
|
if (
|
||||||
|
semver.satisfies(driver.ctx.csiVersion, ">=1.3.0") &&
|
||||||
|
driver.options.service.controller.capabilities.rpc.includes(
|
||||||
|
"VOLUME_CONDITION"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// TODO: let drivers fill ths in
|
||||||
|
volume_condition = { abnormal, message };
|
||||||
|
volume_status.volume_condition = volume_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
async populateCsiVolumeFromData(row) {
|
||||||
|
const driver = this;
|
||||||
|
const zb = await this.getZetabyte();
|
||||||
|
const driverZfsResourceType = this.getDriverZfsResourceType();
|
||||||
|
let datasetName = this.getVolumeParentDatasetName();
|
||||||
|
|
||||||
|
// ignore rows were csi_name is empty
|
||||||
|
if (row[MANAGED_PROPERTY_NAME] != "true") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let volume_content_source;
|
||||||
|
let volume_context = JSON.parse(row[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]);
|
||||||
|
if (
|
||||||
|
zb.helpers.isPropertyValueSet(
|
||||||
|
row[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
volume_context["provisioner_driver"] =
|
||||||
|
row[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
zb.helpers.isPropertyValueSet(
|
||||||
|
row[VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
volume_context["provisioner_driver_instance_id"] =
|
||||||
|
row[VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
zb.helpers.isPropertyValueSet(
|
||||||
|
row[VOLUME_CONTENT_SOURCE_TYPE_PROPERTY_NAME]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
volume_content_source = {};
|
||||||
|
switch (row[VOLUME_CONTENT_SOURCE_TYPE_PROPERTY_NAME]) {
|
||||||
|
case "snapshot":
|
||||||
|
volume_content_source.snapshot = {};
|
||||||
|
volume_content_source.snapshot.snapshot_id =
|
||||||
|
row[VOLUME_CONTENT_SOURCE_ID_PROPERTY_NAME];
|
||||||
|
break;
|
||||||
|
case "volume":
|
||||||
|
volume_content_source.volume = {};
|
||||||
|
volume_content_source.volume.volume_id =
|
||||||
|
row[VOLUME_CONTENT_SOURCE_ID_PROPERTY_NAME];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let volume = {
|
||||||
|
// remove parent dataset info
|
||||||
|
volume_id: row["name"].replace(new RegExp("^" + datasetName + "/"), ""),
|
||||||
|
capacity_bytes:
|
||||||
|
driverZfsResourceType == "filesystem"
|
||||||
|
? row["refquota"]
|
||||||
|
: row["volsize"],
|
||||||
|
content_source: volume_content_source,
|
||||||
|
volume_context,
|
||||||
|
};
|
||||||
|
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure sane options are used etc
|
* Ensure sane options are used etc
|
||||||
* true = ready
|
* true = ready
|
||||||
|
|
@ -1107,6 +1215,86 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
return { available_capacity: properties.available.value };
|
return { available_capacity: properties.available.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single volume
|
||||||
|
*
|
||||||
|
* @param {*} call
|
||||||
|
*/
|
||||||
|
async ControllerGetVolume(call) {
|
||||||
|
const driver = this;
|
||||||
|
const driverZfsResourceType = this.getDriverZfsResourceType();
|
||||||
|
const zb = await this.getZetabyte();
|
||||||
|
|
||||||
|
let datasetParentName = this.getVolumeParentDatasetName();
|
||||||
|
let response;
|
||||||
|
let name = call.request.volume_id;
|
||||||
|
|
||||||
|
if (!datasetParentName) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.FAILED_PRECONDITION,
|
||||||
|
`invalid configuration: missing datasetParentName`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.INVALID_ARGUMENT,
|
||||||
|
`volume_id is required`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const datasetName = datasetParentName + "/" + name;
|
||||||
|
|
||||||
|
let types = [];
|
||||||
|
switch (driverZfsResourceType) {
|
||||||
|
case "filesystem":
|
||||||
|
types = ["filesystem"];
|
||||||
|
break;
|
||||||
|
case "volume":
|
||||||
|
types = ["volume"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
response = await zb.zfs.list(
|
||||||
|
datasetName,
|
||||||
|
[
|
||||||
|
"name",
|
||||||
|
"mountpoint",
|
||||||
|
"refquota",
|
||||||
|
"avail",
|
||||||
|
"used",
|
||||||
|
VOLUME_CSI_NAME_PROPERTY_NAME,
|
||||||
|
VOLUME_CONTENT_SOURCE_TYPE_PROPERTY_NAME,
|
||||||
|
VOLUME_CONTENT_SOURCE_ID_PROPERTY_NAME,
|
||||||
|
"volsize",
|
||||||
|
MANAGED_PROPERTY_NAME,
|
||||||
|
SHARE_VOLUME_CONTEXT_PROPERTY_NAME,
|
||||||
|
SUCCESS_PROPERTY_NAME,
|
||||||
|
VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME,
|
||||||
|
VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME,
|
||||||
|
],
|
||||||
|
{ types, recurse: false }
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.toString().includes("dataset does not exist")) {
|
||||||
|
throw new GrpcError(grpc.status.NOT_FOUND, `volume_id is missing`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
driver.ctx.logger.debug("list volumes result: %j", response);
|
||||||
|
let volume = await driver.populateCsiVolumeFromData(response.indexed[0]);
|
||||||
|
let status = await driver.getVolumeStatus(datasetName);
|
||||||
|
|
||||||
|
let res = { volume };
|
||||||
|
if (status) {
|
||||||
|
res.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TODO: check capability to ensure not asking about block volumes
|
* TODO: check capability to ensure not asking about block volumes
|
||||||
|
|
@ -1213,68 +1401,20 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
entries = [];
|
entries = [];
|
||||||
response.indexed.forEach((row) => {
|
for (let row of response.indexed) {
|
||||||
// ignore rows were csi_name is empty
|
// ignore rows were csi_name is empty
|
||||||
if (row[MANAGED_PROPERTY_NAME] != "true") {
|
if (row[MANAGED_PROPERTY_NAME] != "true") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let volume_content_source;
|
let volume = await driver.populateCsiVolumeFromData(row);
|
||||||
let volume_context = JSON.parse(row[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]);
|
let status = await driver.getVolumeStatus(datasetName);
|
||||||
if (
|
|
||||||
zb.helpers.isPropertyValueSet(
|
|
||||||
row[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
volume_context["provisioner_driver"] =
|
|
||||||
row[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
zb.helpers.isPropertyValueSet(
|
|
||||||
row[VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
volume_context["provisioner_driver_instance_id"] =
|
|
||||||
row[VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
zb.helpers.isPropertyValueSet(
|
|
||||||
row[VOLUME_CONTENT_SOURCE_TYPE_PROPERTY_NAME]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
volume_content_source = {};
|
|
||||||
switch (row[VOLUME_CONTENT_SOURCE_TYPE_PROPERTY_NAME]) {
|
|
||||||
case "snapshot":
|
|
||||||
volume_content_source.snapshot = {};
|
|
||||||
volume_content_source.snapshot.snapshot_id =
|
|
||||||
row[VOLUME_CONTENT_SOURCE_ID_PROPERTY_NAME];
|
|
||||||
break;
|
|
||||||
case "volume":
|
|
||||||
volume_content_source.volume = {};
|
|
||||||
volume_content_source.volume.volume_id =
|
|
||||||
row[VOLUME_CONTENT_SOURCE_ID_PROPERTY_NAME];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.push({
|
entries.push({
|
||||||
volume: {
|
volume,
|
||||||
// remove parent dataset info
|
status,
|
||||||
volume_id: row["name"].replace(
|
|
||||||
new RegExp("^" + datasetName + "/"),
|
|
||||||
""
|
|
||||||
),
|
|
||||||
capacity_bytes:
|
|
||||||
driverZfsResourceType == "filesystem"
|
|
||||||
? row["refquota"]
|
|
||||||
: row["volsize"],
|
|
||||||
content_source: volume_content_source,
|
|
||||||
volume_context,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
if (max_entries && entries.length > max_entries) {
|
if (max_entries && entries.length > max_entries) {
|
||||||
uuid = uuidv4();
|
uuid = uuidv4();
|
||||||
|
|
@ -1365,7 +1505,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
// should only send 1 of snapshot_id or source_volume_id, preferring the former if sent
|
// should only send 1 of snapshot_id or source_volume_id, preferring the former if sent
|
||||||
if (snapshot_id) {
|
if (snapshot_id) {
|
||||||
if (!zb.helpers.isZfsSnapshot(snapshot_id)) {
|
if (!zb.helpers.isZfsSnapshot(snapshot_id)) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
operativeFilesystem = volumeParentDatasetName + "/" + snapshot_id;
|
operativeFilesystem = volumeParentDatasetName + "/" + snapshot_id;
|
||||||
operativeFilesystemType = 3;
|
operativeFilesystemType = 3;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ const { GrpcError, grpc } = require("../utils/grpc");
|
||||||
const { Mount } = require("../utils/mount");
|
const { Mount } = require("../utils/mount");
|
||||||
const { Filesystem } = require("../utils/filesystem");
|
const { Filesystem } = require("../utils/filesystem");
|
||||||
const { ISCSI } = require("../utils/iscsi");
|
const { ISCSI } = require("../utils/iscsi");
|
||||||
|
const semver = require("semver");
|
||||||
const sleep = require("../utils/general").sleep;
|
const sleep = require("../utils/general").sleep;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -867,6 +868,7 @@ class CsiBaseDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
async NodeGetVolumeStats(call) {
|
async NodeGetVolumeStats(call) {
|
||||||
|
const driver = this;
|
||||||
const mount = new Mount();
|
const mount = new Mount();
|
||||||
const filesystem = new Filesystem();
|
const filesystem = new Filesystem();
|
||||||
let result;
|
let result;
|
||||||
|
|
@ -880,6 +882,19 @@ class CsiBaseDriver {
|
||||||
throw new GrpcError(grpc.status.INVALID_ARGUMENT, `missing volume_path`);
|
throw new GrpcError(grpc.status.INVALID_ARGUMENT, `missing volume_path`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let res = {};
|
||||||
|
|
||||||
|
//VOLUME_CONDITION
|
||||||
|
if (
|
||||||
|
semver.satisfies(driver.ctx.csiVersion, ">=1.3.0") &&
|
||||||
|
options.service.node.capabilities.rpc.includes("VOLUME_CONDITION")
|
||||||
|
) {
|
||||||
|
// TODO: let drivers fill ths in
|
||||||
|
let abnormal = false;
|
||||||
|
let message = "OK";
|
||||||
|
res.volume_condition = { abnormal, message };
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(await mount.isBindMountedBlockDevice(volume_path)) ||
|
(await mount.isBindMountedBlockDevice(volume_path)) ||
|
||||||
(await mount.isBindMountedBlockDevice(block_path))
|
(await mount.isBindMountedBlockDevice(block_path))
|
||||||
|
|
@ -895,33 +910,33 @@ class CsiBaseDriver {
|
||||||
case "mount":
|
case "mount":
|
||||||
result = await mount.getMountDetails(device_path);
|
result = await mount.getMountDetails(device_path);
|
||||||
|
|
||||||
return {
|
res.usage = [
|
||||||
usage: [
|
{
|
||||||
{
|
available: result.avail,
|
||||||
available: result.avail,
|
total: result.size,
|
||||||
total: result.size,
|
used: result.used,
|
||||||
used: result.used,
|
unit: "BYTES",
|
||||||
unit: "BYTES",
|
},
|
||||||
},
|
];
|
||||||
],
|
break;
|
||||||
};
|
|
||||||
case "block":
|
case "block":
|
||||||
result = await filesystem.getBlockDevice(device_path);
|
result = await filesystem.getBlockDevice(device_path);
|
||||||
|
|
||||||
return {
|
res.usage = [
|
||||||
usage: [
|
{
|
||||||
{
|
total: result.size,
|
||||||
total: result.size,
|
unit: "BYTES",
|
||||||
unit: "BYTES",
|
},
|
||||||
},
|
];
|
||||||
],
|
break;
|
||||||
};
|
|
||||||
default:
|
default:
|
||||||
throw new GrpcError(
|
throw new GrpcError(
|
||||||
grpc.status.INVALID_ARGUMENT,
|
grpc.status.INVALID_ARGUMENT,
|
||||||
`unsupported/unknown access_type ${access_type}`
|
`unsupported/unknown access_type ${access_type}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue