support TN 25.04, env vars in config, improved Dockerfiles

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen 2025-04-05 17:16:52 -06:00
parent d05fe2c4f4
commit 957d7fc6bc
13 changed files with 5955 additions and 181 deletions

View File

@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y locales && rm -rf /var/lib/apt/lists/*
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG=en_US.utf8 ENV LANG=en_US.utf8
ENV NODE_VERSION=v20.11.1 ENV NODE_VERSION=v20.19.0
ENV NODE_ENV=production ENV NODE_ENV=production
# install build deps # install build deps
@ -80,18 +80,24 @@ RUN apt-get update && \
apt-get install -y wget netbase zip bzip2 socat e2fsprogs exfatprogs xfsprogs btrfs-progs fatresize dosfstools ntfs-3g nfs-common cifs-utils fdisk gdisk cloud-guest-utils sudo rsync procps util-linux nvme-cli fuse3 && \ apt-get install -y wget netbase zip bzip2 socat e2fsprogs exfatprogs xfsprogs btrfs-progs fatresize dosfstools ntfs-3g nfs-common cifs-utils fdisk gdisk cloud-guest-utils sudo rsync procps util-linux nvme-cli fuse3 && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
ARG RCLONE_VERSION=1.66.0 # TODO: remove nvme unique files
ARG RCLONE_VERSION=1.69.1
ADD docker/rclone-installer.sh /usr/local/sbin ADD docker/rclone-installer.sh /usr/local/sbin
RUN chmod +x /usr/local/sbin/rclone-installer.sh && rclone-installer.sh RUN chmod +x /usr/local/sbin/rclone-installer.sh && rclone-installer.sh
ARG RESTIC_VERSION=0.16.4 ARG RESTIC_VERSION=0.18.0
ADD docker/restic-installer.sh /usr/local/sbin ADD docker/restic-installer.sh /usr/local/sbin
RUN chmod +x /usr/local/sbin/restic-installer.sh && restic-installer.sh RUN chmod +x /usr/local/sbin/restic-installer.sh && restic-installer.sh
ARG KOPIA_VERSION=0.16.1 ARG KOPIA_VERSION=0.19.0
ADD docker/kopia-installer.sh /usr/local/sbin ADD docker/kopia-installer.sh /usr/local/sbin
RUN chmod +x /usr/local/sbin/kopia-installer.sh && kopia-installer.sh RUN chmod +x /usr/local/sbin/kopia-installer.sh && kopia-installer.sh
ARG YQ_VERSION=v4.45.1
ADD docker/yq-installer.sh /usr/local/sbin
RUN chmod +x /usr/local/sbin/yq-installer.sh && yq-installer.sh
# controller requirements # controller requirements
#RUN apt-get update && \ #RUN apt-get update && \
# apt-get install -y ansible && \ # apt-get install -y ansible && \

View File

@ -3,9 +3,11 @@
# https://github.com/kubernetes/kubernetes/blob/master/test/images/busybox/Dockerfile_windows # https://github.com/kubernetes/kubernetes/blob/master/test/images/busybox/Dockerfile_windows
# https://github.com/kubernetes/kubernetes/tree/master/test/images#windows-test-images-considerations # https://github.com/kubernetes/kubernetes/tree/master/test/images#windows-test-images-considerations
# https://stefanscherer.github.io/find-dependencies-in-windows-containers/ # https://stefanscherer.github.io/find-dependencies-in-windows-containers/
# # https://stackoverflow.com/questions/65104246/how-to-install-powershell-core-in-aspnet-nanoserver-docker-container
#
# docker build --build-arg NANO_BASE_TAG=1809 --build-arg CORE_BASE_TAG=ltsc2019 -t foobar -f Dockerfile.Windows . # docker build --build-arg NANO_BASE_TAG=1809 --build-arg CORE_BASE_TAG=ltsc2019 -t foobar -f Dockerfile.Windows .
# docker run --rm -ti --entrypoint powershell foobar # docker run --rm -ti --entrypoint powershell foobar
# docker run --rm -ti --entrypoint cmd foobar
# docker run --rm foobar # docker run --rm foobar
# docker save foobar -o foobar.tar # docker save foobar -o foobar.tar
# buildah pull docker-archive:foobar.tar # buildah pull docker-archive:foobar.tar
@ -16,85 +18,96 @@
ARG NANO_BASE_TAG ARG NANO_BASE_TAG
ARG CORE_BASE_TAG ARG CORE_BASE_TAG
FROM mcr.microsoft.com/windows/servercore:${CORE_BASE_TAG} as powershell
# install powershell
ENV PS_VERSION=6.2.7
ADD https://github.com/PowerShell/PowerShell/releases/download/v$PS_VERSION/PowerShell-$PS_VERSION-win-x64.zip /PowerShell/powershell.zip
RUN cd C:\PowerShell &\
tar.exe -xf powershell.zip &\
del powershell.zip &\
mklink powershell.exe pwsh.exe
FROM mcr.microsoft.com/windows/servercore:${CORE_BASE_TAG} as build FROM mcr.microsoft.com/windows/servercore:${CORE_BASE_TAG} as build
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
#ENV GPG_VERSION 4.0.2 ENV POWERSHELL_TELEMETRY_OPTOUT="1"
ENV GPG_VERSION 2.3.4
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; \ ARG PS_VERSION=7.5.0
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait ADD https://github.com/PowerShell/PowerShell/releases/download/v$PS_VERSION/PowerShell-$PS_VERSION-win-x64.zip /PowerShell/powershell.zip
# https://github.com/nodejs/node#release-keys RUN \
RUN @( \ Expand-Archive '/PowerShell/powershell.zip' -DestinationPath '/PowerShell' ; \
'4ED778F539E3634C779C87C6D7062848A1AB005C', \ cd C:\PowerShell ; \
'141F07595B7B3FFE74309A937405533BE57C7D57', \ del powershell.zip ; \
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', \ New-Item -ItemType SymbolicLink -Path "powershell.exe" -Target "pwsh.exe"
'74F12602B6F1C4E913FAA37AD3A89613643B6201', \
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', \
'61FC681DFB92A079F1685E77973F295594EC4689', \
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', \
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', \
'C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C', \
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', \
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', \
'108F52B48DB57BB0CC439B2997B01419BD92F80A', \
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' \
) | foreach { \
gpg --keyserver hkps://keys.openpgp.org --recv-keys $_ ; \
}
ENV NODE_VERSION 16.18.0
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ;
#RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; \
# gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
#gpg --verify SHASUMS256.txt.sig SHASUMS256.txt
ENV NODE_VERSION 20.19.0
ENV NODE_ENV=production
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \ RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; \ Expand-Archive node.zip -DestinationPath C:\ ; \
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; \ Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
Expand-Archive node.zip -DestinationPath C:\ ; \
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
RUN mkdir \usr\local\bin; mkdir \tmp
ARG RCLONE_VERSION=v1.69.1
RUN Invoke-WebRequest "https://github.com/rclone/rclone/releases/download/${env:RCLONE_VERSION}/rclone-${env:RCLONE_VERSION}-windows-amd64.zip" -OutFile '/tmp/rclone.zip' -UseBasicParsing ; \
Expand-Archive C:\tmp\rclone.zip -DestinationPath C:\tmp ; \
Copy-Item $('C:\tmp\rclone-{0}-windows-amd64\rclone.exe' -f $env:RCLONE_VERSION) -Destination "C:\usr\local\bin"
ARG RESTIC_VERSION=0.18.0
RUN Invoke-WebRequest "https://github.com/restic/restic/releases/download/v${env:RESTIC_VERSION}/restic_${env:RESTIC_VERSION}_windows_amd64.zip" -OutFile '/tmp/restic.zip' -UseBasicParsing ; \
Expand-Archive C:\tmp\restic.zip -DestinationPath C:\tmp ; \
Copy-Item $('C:\tmp\restic_{0}_windows_amd64.exe' -f $env:RESTIC_VERSION) -Destination "C:\usr\local\bin\restic.exe"
ARG KOPIA_VERSION=0.19.0
RUN Invoke-WebRequest "https://github.com/kopia/kopia/releases/download/v${env:KOPIA_VERSION}/kopia-${env:KOPIA_VERSION}-windows-x64.zip" -OutFile '/tmp/kopia.zip' -UseBasicParsing ; \
Expand-Archive C:\tmp\kopia.zip -DestinationPath C:\tmp ; \
Copy-Item $('C:\tmp\kopia-{0}-windows-x64\kopia.exe' -f $env:KOPIA_VERSION) -Destination "C:\usr\local\bin"
ARG YQ_VERSION=v4.45.1
RUN Invoke-WebRequest "https://github.com/mikefarah/yq/releases/download/${env:YQ_VERSION}/yq_windows_amd64.zip" -OutFile '/tmp/yq.zip' -UseBasicParsing ; \
Expand-Archive C:\tmp\yq.zip -DestinationPath C:\tmp ; \
Copy-Item $('C:\tmp\yq_windows_amd64.exe') -Destination "C:\usr\local\bin\yq.exe"
RUN Remove-Item C:\tmp\ -Force -Recurse
# install app
#RUN setx /M PATH "%PATH%;C:\nodejs" #RUN setx /M PATH "%PATH%;C:\nodejs"
RUN setx /M PATH $(${Env:PATH} + \";C:\nodejs\") RUN setx /M PATH $(${Env:PATH} + \";C:\nodejs\")
RUN node --version; npm --version; RUN node --version; npm --version;
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
RUN npm install --only=production; ls / RUN npm install --only=production; ls /
COPY . . COPY . .
######################
# actual image
######################
FROM mcr.microsoft.com/windows/nanoserver:${NANO_BASE_TAG} FROM mcr.microsoft.com/windows/nanoserver:${NANO_BASE_TAG}
SHELL ["cmd.exe", "/s" , "/c"]
#https://github.com/PowerShell/PowerShell-Docker/issues/236
# NOTE: this works for non-host process containers, but host process containers will have specials PATH requirements
# C:\Windows\System32\WindowsPowerShell\v1.0\
ENV PATH="C:\Windows\system32;C:\Windows;C:\PowerShell;C:\app\bin;"
ENV DEMOCRATIC_CSI_IS_CONTAINER=true
ENV NODE_ENV=production
LABEL org.opencontainers.image.source https://github.com/democratic-csi/democratic-csi LABEL org.opencontainers.image.source https://github.com/democratic-csi/democratic-csi
LABEL org.opencontainers.image.url https://github.com/democratic-csi/democratic-csi LABEL org.opencontainers.image.url https://github.com/democratic-csi/democratic-csi
LABEL org.opencontainers.image.licenses MIT LABEL org.opencontainers.image.licenses MIT
# if additional dlls are required can copy like this # install powershell
#COPY --from=build /Windows/System32/nltest.exe /Windows/System32/nltest.exe COPY --from=build /PowerShell /PowerShell
# install app
COPY --from=build /app /app COPY --from=build /app /app
WORKDIR /app WORKDIR /app
# this works for both host-process and non-host-process container semantics
COPY --from=build /nodejs/node.exe ./bin COPY --from=build /nodejs/node.exe ./bin
COPY --from=build /usr/local/bin/ ./bin
ENTRYPOINT [ "bin/node.exe", "--expose-gc", "bin/democratic-csi" ] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"]
EXPOSE 50051
# this works for both host-process and non-host-process container semantics
#ENTRYPOINT [ "bin/node.exe", "--expose-gc", "bin/democratic-csi" ]
ADD docker/entrypoint.ps1 ./bin
# NOTE: this powershell.exe could be problematic based on overriding PATH in container vs host etc
ENTRYPOINT [ "powershell.exe", "bin/entrypoint.ps1" ]

View File

@ -10,7 +10,12 @@ require("../src/utils/polyfills");
const yaml = require("js-yaml"); const yaml = require("js-yaml");
const fs = require("fs"); const fs = require("fs");
const { grpc } = require("../src/utils/grpc"); const { grpc } = require("../src/utils/grpc");
const { stringify, stripWindowsDriveLetter } = require("../src/utils/general"); const {
stringify,
stripWindowsDriveLetter,
expandenv,
} = require("../src/utils/general");
const traverse = require("traverse");
let driverConfigFile; let driverConfigFile;
let options; let options;
@ -67,6 +72,8 @@ const args = require("yargs")
"1.7.0", "1.7.0",
"1.8.0", "1.8.0",
"1.9.0", "1.9.0",
"1.10.0",
"1.11.0",
], ],
}) })
.demandOption(["csi-version"], "csi-version is required") .demandOption(["csi-version"], "csi-version is required")
@ -106,6 +113,20 @@ if (!args.serverSocket && !args.serverAddress && !args.serverPort) {
process.exit(1); process.exit(1);
} }
//console.log(JSON.stringify(options, null, 2));
traverse(options).forEach(function (v) {
if (typeof v === "string" || v instanceof String) {
v = expandenv(v);
try {
v = JSON.parse(v);
} catch (e) {
// ignore
}
this.update(v);
}
});
//console.log(JSON.stringify(options, null, 2));
//process.exit(1);
//console.log(args); //console.log(args);
//console.log(process.env); //console.log(process.env);
@ -529,6 +550,9 @@ if (process.env.LOG_GRPC_SESSIONS == "1") {
if (require.main === module) { if (require.main === module) {
(async function () { (async function () {
try { try {
//nvme gen-hostnqn > /etc/nvme/hostnqn
//uuidgen > /etc/nvme/hostid
if (bindAddress) { if (bindAddress) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
csiServer.bindAsync( csiServer.bindAsync(

2103
csi_proto/csi-v1.10.0.proto Normal file

File diff suppressed because it is too large Load Diff

2078
csi_proto/csi-v1.11.0.proto Normal file

File diff suppressed because it is too large Load Diff

6
docker/entrypoint.ps1 Normal file
View File

@ -0,0 +1,6 @@
write-host "starting democratic-csi via entrypoint.ps1"
$env:Path = "${pwd}\bin;${env:Path}"
.\bin\node.exe --expose-gc .\bin\democratic-csi @args
Exit $LASTEXITCODE

38
docker/yq-installer.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/bash
set -e
set -x
PLATFORM_TYPE=${1}
if [[ "${PLATFORM_TYPE}" == "build" ]]; then
PLATFORM=$BUILDPLATFORM
else
PLATFORM=$TARGETPLATFORM
fi
if [[ "x${PLATFORM}" == "x" ]]; then
PLATFORM="linux/amd64"
fi
# these come from the --platform option of buildx, indirectly from DOCKER_BUILD_PLATFORM in main.yaml
if [ "$PLATFORM" = "linux/amd64" ]; then
export PLATFORM_ARCH="amd64"
elif [ "$PLATFORM" = "linux/arm64" ]; then
export PLATFORM_ARCH="arm64"
elif [ "$PLATFORM" = "linux/arm/v7" ]; then
export PLATFORM_ARCH="arm"
elif [ "$PLATFORM" = "linux/s390x" ]; then
export PLATFORM_ARCH="s390x"
elif [ "$PLATFORM" = "linux/ppc64le" ]; then
export PLATFORM_ARCH="ppc64le"
else
echo "unsupported/unknown yq PLATFORM ${PLATFORM}"
exit 0
fi
echo "I am installing yq $YQ_VERSION"
wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${PLATFORM_ARCH} -O /usr/local/bin/yq
chmod +x /usr/local/bin/yq

View File

@ -4,63 +4,67 @@ Some drivers support different settings for volumes. These can be configured via
classes. classes.
## `synology-iscsi` ## `synology-iscsi`
The `synology-iscsi` driver supports several storage class parameters. Note however that not all parameters/values are The `synology-iscsi` driver supports several storage class parameters. Note however that not all parameters/values are
supported for all backing file systems and LUN type. The following options are available: supported for all backing file systems and LUN type. The following options are available:
### Configure Storage Classes ### Configure Storage Classes
```yaml ```yaml
apiVersion: storage.k8s.io/v1 apiVersion: storage.k8s.io/v1
kind: StorageClass kind: StorageClass
metadata: metadata:
name: synology-iscsi name: synology-iscsi
parameters: parameters:
fsType: ext4 fsType: ext4
# The following options affect the LUN representing the volume. These options are passed directly to the Synology API. # The following options affect the LUN representing the volume. These options are passed directly to the Synology API.
# The following options are known. # The following options are known.
lunTemplate: | lunTemplate: |
type: BLUN # Btrfs thin provisioning type: BLUN # Btrfs thin provisioning
type: BLUN_THICK # Btrfs thick provisioning type: BLUN_THICK # Btrfs thick provisioning
type: THIN # Ext4 thin provisioning type: THIN # Ext4 thin provisioning
type: ADV # Ext4 thin provisioning with legacy advanced feature set type: ADV # Ext4 thin provisioning with legacy advanced feature set
type: FILE # Ext4 thick provisioning type: FILE # Ext4 thick provisioning
description: Some Description description: Some Description
# Only for thick provisioned volumes. Known values:
# 0: Buffered Writes
# 3: Direct Write
direct_io_pattern: 0
# Device Attributes. See below for more info
dev_attribs:
- dev_attrib: emulate_tpws
enable: 1
- ...
# The following options affect the iSCSI target. These options will be passed directly to the Synology API. # Only for thick provisioned volumes. Known values:
# The following options are known. # 0: Buffered Writes
targetTemplate: | # 3: Direct Write
has_header_checksum: false direct_io_pattern: 0
has_data_checksum: false
# Note that this option requires a compatible filesystem. Use 0 for unlimited sessions.
max_sessions: 0
multi_sessions: true
max_recv_seg_bytes: 262144
max_send_seg_bytes: 262144
# Use this to disable authentication. To configure authentication see below # Device Attributes. See below for more info
auth_type: 0 dev_attribs:
- dev_attrib: emulate_tpws
enable: 1
- ...
# The following options affect the iSCSI target. These options will be passed directly to the Synology API.
# The following options are known.
targetTemplate: |
has_header_checksum: false
has_data_checksum: false
# Note that this option requires a compatible filesystem. Use 0 for unlimited sessions.
max_sessions: 0
multi_sessions: true
max_recv_seg_bytes: 262144
max_send_seg_bytes: 262144
# Use this to disable authentication. To configure authentication see below
auth_type: 0
``` ```
#### About LUN Types #### About LUN Types
The availability of the different types of LUNs depends on the filesystem used on your Synology volume. For Btrfs volumes The availability of the different types of LUNs depends on the filesystem used on your Synology volume. For Btrfs volumes
you can use `BLUN` and `BLUN_THICK` volumes. For Ext4 volumes you can use `THIN`, `ADV` or `FILE` volumes. These you can use `BLUN` and `BLUN_THICK` volumes. For Ext4 volumes you can use `THIN`, `ADV` or `FILE` volumes. These
correspond to the options available in the UI. correspond to the options available in the UI.
#### About `dev_attribs` #### About `dev_attribs`
Most of the LUN options are configured via the `dev_attribs` list. This list can be specified both in the `lunTemplate` Most of the LUN options are configured via the `dev_attribs` list. This list can be specified both in the `lunTemplate`
of the global configuration and in the `lunTemplate` of the `StorageClass`. If both lists are present they will be merged of the global configuration and in the `lunTemplate` of the `StorageClass`. If both lists are present they will be merged
(with the `StorageClass` taking precedence). The following `dev_attribs` are known to work: (with the `StorageClass` taking precedence). The following `dev_attribs` are known to work:
- `emulate_tpws`: Hardware-assisted zeroing - `emulate_tpws`: Hardware-assisted zeroing
- `emulate_caw`: Hardware-assisted locking - `emulate_caw`: Hardware-assisted locking
@ -71,6 +75,7 @@ of the global configuration and in the `lunTemplate` of the `StorageClass`. If b
- `can_snapshot`: Enable snapshots for this volume. Only works for thin provisioned volumes. - `can_snapshot`: Enable snapshots for this volume. Only works for thin provisioned volumes.
### Configure Snapshot Classes ### Configure Snapshot Classes
`synology-iscsi` can also configure different parameters on snapshot classes: `synology-iscsi` can also configure different parameters on snapshot classes:
```yaml ```yaml
@ -82,18 +87,18 @@ parameters:
# This inline yaml object will be passed to the Synology API when creating the snapshot. # This inline yaml object will be passed to the Synology API when creating the snapshot.
lunSnapshotTemplate: | lunSnapshotTemplate: |
is_locked: true is_locked: true
# https://kb.synology.com/en-me/DSM/tutorial/What_is_file_system_consistent_snapshot # https://kb.synology.com/en-me/DSM/tutorial/What_is_file_system_consistent_snapshot
# Note that app consistent snapshots require a working Synology Storage Console. Otherwise both values will have # Note that app consistent snapshots require a working Synology Storage Console. Otherwise both values will have
# equivalent behavior. # equivalent behavior.
is_app_consistent: true is_app_consistent: true
...
``` ```
Note that it is currently not supported by Synology devices to restore a snapshot onto a different volume. You can Note that it is currently not supported by Synology devices to restore a snapshot onto a different volume. You can
create volumes from snapshots, but you should use the same `StorageClass` as the original volume of the snapshot did. create volumes from snapshots, but you should use the same `StorageClass` as the original volume of the snapshot did.
### Enabling CHAP Authentication ### Enabling CHAP Authentication
You can enable CHAP Authentication for `StorageClass`es by supplying an appropriate `StorageClass` secret (see the You can enable CHAP Authentication for `StorageClass`es by supplying an appropriate `StorageClass` secret (see the
[documentation](https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html) for more details). You [documentation](https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html) for more details). You
can use the same password for alle volumes of a `StorageClass` or use different passwords per volume. can use the same password for alle volumes of a `StorageClass` or use different passwords per volume.
@ -123,12 +128,17 @@ kind: Secret
metadata: metadata:
name: chap-secret name: chap-secret
stringData: stringData:
# Client Credentials lunTemplate: |
user: client ...
password: MySecretPassword targetTemplate: |
# Mutual CHAP Credentials. If these are specified mutual CHAP will be enabled. # Client Credentials
mutualUser: server user: client
mutualPassword: MyOtherPassword password: MySecretPassword
# Mutual CHAP Credentials. If these are specified mutual CHAP will be enabled.
mutualUser: server
mutualPassword: MyOtherPassword
lunSnapshotTemplate: |
...
``` ```
Note that CHAP authentication will only be enabled if the secret contains a username and password. If e.g. a password is Note that CHAP authentication will only be enabled if the secret contains a username and password. If e.g. a password is

1551
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"semver": "^7.3.4", "semver": "^7.3.4",
"ssh2": "^1.1.0", "ssh2": "^1.1.0",
"traverse": "^0.6.11",
"uri-js": "^4.4.1", "uri-js": "^4.4.1",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"winston": "^3.6.0", "winston": "^3.6.0",

View File

@ -1798,8 +1798,13 @@ class FreeNASApiDriver extends CsiBaseDriver {
async removeSnapshotsFromDatatset(datasetName) { async removeSnapshotsFromDatatset(datasetName) {
const httpApiClient = await this.getTrueNASHttpApiClient(); const httpApiClient = await this.getTrueNASHttpApiClient();
// const httpClient = await this.getHttpClient();
// const major = await httpApiClient.getSystemVersionMajor();
let job_id = await httpApiClient.DatasetDestroySnapshots(datasetName); let job_id = await httpApiClient.DatasetDestroySnapshots(datasetName);
await httpApiClient.CoreWaitForJob(job_id, 30); if (job_id) {
await httpApiClient.CoreWaitForJob(job_id, 30);
}
} }
/** /**
@ -2033,10 +2038,13 @@ class FreeNASApiDriver extends CsiBaseDriver {
} }
async getTrueNASHttpApiClient() { async getTrueNASHttpApiClient() {
return this.ctx.registry.getAsync(`${__REGISTRY_NS__}:api_client`, async () => { return this.ctx.registry.getAsync(
const httpClient = await this.getHttpClient(); `${__REGISTRY_NS__}:api_client`,
return new TrueNASApiClient(httpClient, this.ctx.cache); async () => {
}); const httpClient = await this.getHttpClient();
return new TrueNASApiClient(httpClient, this.ctx.cache);
}
);
} }
getAccessModes(capability) { getAccessModes(capability) {

View File

@ -1,6 +1,7 @@
const _ = require("lodash");
const { sleep, stringify } = require("../../../utils/general"); const { sleep, stringify } = require("../../../utils/general");
const { Zetabyte } = require("../../../utils/zfs"); const { Zetabyte } = require("../../../utils/zfs");
const { Registry } = require("../../../utils/registry");
// used for in-memory cache of the version info // used for in-memory cache of the version info
const FREENAS_SYSTEM_VERSION_CACHE_KEY = "freenas:system_version"; const FREENAS_SYSTEM_VERSION_CACHE_KEY = "freenas:system_version";
@ -11,6 +12,7 @@ class Api {
this.client = client; this.client = client;
this.cache = cache; this.cache = cache;
this.options = options; this.options = options;
this.registry = new Registry();
} }
async getHttpClient() { async getHttpClient() {
@ -22,7 +24,7 @@ class Api {
* @returns * @returns
*/ */
async getZetabyte() { async getZetabyte() {
return this.ctx.registry.get(`${__REGISTRY_NS__}:zb`, () => { return this.registry.get(`${__REGISTRY_NS__}:zb`, () => {
return new Zetabyte({ return new Zetabyte({
executor: { executor: {
spawn: function () { spawn: function () {
@ -422,13 +424,13 @@ class Api {
* @param {*} properties * @param {*} properties
* @returns * @returns
*/ */
async DatasetGet(datasetName, properties) { async DatasetGet(datasetName, properties, queryParams = {}) {
const httpClient = await this.getHttpClient(false); const httpClient = await this.getHttpClient(false);
let response; let response;
let endpoint; let endpoint;
endpoint = `/pool/dataset/id/${encodeURIComponent(datasetName)}`; endpoint = `/pool/dataset/id/${encodeURIComponent(datasetName)}`;
response = await httpClient.get(endpoint); response = await httpClient.get(endpoint, queryParams);
if (response.statusCode == 200) { if (response.statusCode == 200) {
return this.normalizeProperties(response.body, properties); return this.normalizeProperties(response.body, properties);
@ -441,28 +443,60 @@ class Api {
throw new Error(JSON.stringify(response.body)); throw new Error(JSON.stringify(response.body));
} }
/**
* This is meant to destroy all snapshots on the given dataset
*
* @param {*} datasetName
* @param {*} data
* @returns
*/
async DatasetDestroySnapshots(datasetName, data = {}) { async DatasetDestroySnapshots(datasetName, data = {}) {
const httpClient = await this.getHttpClient(false); const httpClient = await this.getHttpClient(false);
let response; let response;
let endpoint; let endpoint;
data.name = datasetName; const major = await this.getSystemVersionMajor();
if (Number(major) >= 25) {
try {
response = await this.DatasetGet(
datasetName,
["id", "type", "name", "pool", "snapshots"],
{
"extra.snapshots": "true",
"extra.retrieve_children": "false",
}
);
endpoint = "/pool/dataset/destroy_snapshots"; for (const snapshot of _.get(response, "snapshots", [])) {
response = await httpClient.post(endpoint, data); await this.SnapshotDelete(snapshot.name, {
defer: true,
});
}
} catch (err) {
if (err.toString().includes("dataset does not exist")) {
return;
}
throw err;
}
} else {
data.name = datasetName;
if (response.statusCode == 200) { endpoint = "/pool/dataset/destroy_snapshots";
return response.body; response = await httpClient.post(endpoint, data);
if (response.statusCode == 200) {
return response.body;
}
if (
response.statusCode == 422 &&
JSON.stringify(response.body).includes("already exists")
) {
return;
}
throw new Error(JSON.stringify(response.body));
} }
if (
response.statusCode == 422 &&
JSON.stringify(response.body).includes("already exists")
) {
return;
}
throw new Error(JSON.stringify(response.body));
} }
async SnapshotSet(snapshotName, properties) { async SnapshotSet(snapshotName, properties) {

View File

@ -272,6 +272,19 @@ async function hostname_lookup(hostname) {
}); });
} }
function expandenv(string, env) {
if (!(typeof string === "string" || string instanceof String)) {
throw new Error("Please pass a string into expandenv");
}
env = env ? env : process.env;
return string.replace(/\$\{?[a-zA-Z_]+[a-zA-Z0-9_]*\}?/g, function (match) {
match = match.replace(/[^A-Za-z0-9_]/g, "");
return env[match] || "";
});
}
module.exports.sleep = sleep; module.exports.sleep = sleep;
module.exports.md5 = md5; module.exports.md5 = md5;
module.exports.crc32 = crc32; module.exports.crc32 = crc32;
@ -292,3 +305,4 @@ module.exports.default_supported_file_filesystems =
module.exports.retry = retry; module.exports.retry = retry;
module.exports.trimchar = trimchar; module.exports.trimchar = trimchar;
module.exports.hostname_lookup = hostname_lookup; module.exports.hostname_lookup = hostname_lookup;
module.exports.expandenv = expandenv;