Scripts
replace.sh
Use the below script to replace a drive. See replacing a drive for more information on how to use this script.
#!/usr/bin/env bash
#
# This file is part of MinIO DirectPV
# Copyright (c) 2023 MinIO, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This script replaces source drive to destination drive in the specified node
#
set -e
# usage: get_drive_id <node> <drive-name>
function get_drive_id() {
kubectl get directpvdrives \
--selector="directpv.min.io/node==${1},directpv.min.io/drive-name==${2}" \
-o go-template='{{range .items}}{{.metadata.name}}{{end}}'
}
# usage: get_volumes <drive-id>
function get_volumes() {
kubectl get directpvvolumes \
--selector="directpv.min.io/drive=${1}" \
-o go-template='{{range .items}}{{.metadata.name}}{{ " " | print }}{{end}}'
}
# usage: get_pod_name <volume>
function get_pod_name() {
# shellcheck disable=SC2016
kubectl get directpvvolumes "${1}" \
-o go-template='{{range $k,$v := .metadata.labels}}{{if eq $k "directpv.min.io/pod.name"}}{{$v}}{{end}}{{end}}'
}
# usage: get_pod_namespace <volume>
function get_pod_namespace() {
# shellcheck disable=SC2016
kubectl get directpvvolumes "${1}" \
-o go-template='{{range $k,$v := .metadata.labels}}{{if eq $k "directpv.min.io/pod.namespace"}}{{$v}}{{end}}{{end}}'
}
function init() {
if [[ $# -eq 4 ]]; then
echo "usage: replace.sh <NODE> <SRC-DRIVE> <DEST-DRIVE>"
echo
echo "This script replaces source drive to destination drive in the specified node"
exit 255
fi
if ! which kubectl >/dev/null 2>&1; then
echo "kubectl not found; please install"
exit 255
fi
if ! kubectl directpv --version >/dev/null 2>&1; then
echo "kubectl directpv not found; please install"
exit 255
fi
}
function main() {
node="$1"
src_drive="${2#/dev/}"
dest_drive="${3#/dev/}"
# Get source drive ID
src_drive_id=$(get_drive_id "${node}" "${src_drive}")
if [ -z "${src_drive_id}" ]; then
echo "source drive ${src_drive} on node ${node} not found"
exit 1
fi
# Get destination drive ID
dest_drive_id=$(get_drive_id "${node}" "${dest_drive}")
if [ -z "${dest_drive_id}" ]; then
echo "destination drive ${dest_drive} on node ${node} not found"
exit 1
fi
# Cordon source and destination drives
if ! kubectl directpv cordon "${src_drive_id}" "${dest_drive_id}"; then
echo "unable to cordon drives"
exit 1
fi
# Cordon kubernetes node
if ! kubectl cordon "${node}"; then
echo "unable to cordon node ${node}"
exit 1
fi
mapfile -t volumes < <(get_volumes "${src_drive_id}")
IFS=' ' read -r -a volumes_arr <<< "${volumes[@]}"
for volume in "${volumes_arr[@]}"; do
pod_name=$(get_pod_name "${volume}")
pod_namespace=$(get_pod_namespace "${volume}")
if ! kubectl delete pod "${pod_name}" --namespace "${pod_namespace}"; then
echo "unable to delete pod ${pod_name} using volume ${volume}"
exit 1
fi
done
if [ "${#volumes_arr[@]}" -gt 0 ]; then
# Wait for associated DirectPV volumes to be unbound
while kubectl directpv list volumes --no-headers "${volumes_arr[@]}" | grep -q Bounded; do
echo "...waiting for volumes to be unbound"
sleep 10
done
else
echo "no volumes found in source drive ${src_drive} on node ${node}"
fi
# Run move command
kubectl directpv move "${src_drive_id}" "${dest_drive_id}"
# Uncordon destination drive
kubectl directpv uncordon "${dest_drive_id}"
# Uncordon kubernetes node
kubectl uncordon "${node}"
}
init "$@"
main "$@"
push-images.sh
Use this script to push all required images to a private registry.
push-images.sh example.org/myuser
#!/usr/bin/env bash
#
# This file is part of MinIO DirectPV
# Copyright (c) 2023 MinIO, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This script pushes DirectPV and its sidecar images to private registry.
#
set -o errexit
set -o nounset
set -o pipefail
declare registry podman
function init() {
if [ "$#" -ne 1 ]; then
cat <<EOF
USAGE:
push-images.sh <REGISTRY>
ARGUMENT:
<REGISTRY> Image registry without 'http' prefix.
EXAMPLE:
$ push-images.sh example.org/myuser
EOF
exit 255
fi
registry="$1"
if which podman >/dev/null 2>&1; then
podman=podman
elif which docker >/dev/null 2>&1; then
podman=docker
else
echo "no podman or docker found; please install"
exit 255
fi
}
# usage: push_image <image>
function push_image() {
image="$1"
private_image="${image/quay.io\/minio/$registry}"
echo "Pushing image ${image}"
"${podman}" pull --quiet "${image}"
"${podman}" tag "${image}" "${private_image}"
"${podman}" push --quiet "${private_image}"
}
function main() {
push_image "quay.io/minio/csi-node-driver-registrar:v2.6.3"
push_image "quay.io/minio/csi-provisioner:v3.4.0"
push_image "quay.io/minio/csi-provisioner:v2.2.0-go1.18"
push_image "quay.io/minio/livenessprobe:v2.9.0"
push_image "quay.io/minio/csi-resizer:v1.7.0"
release=$(curl -sfL "https://api.github.com/repos/minio/directpv/releases/latest" | awk '/tag_name/ { print substr($2, 3, length($2)-4) }')
push_image "quay.io/minio/directpv:v${release}"
}
init "$@"
main "$@"
remove-node.sh
Use this script to remove an empty node no longer needed for DirectPV.
#!/usr/bin/env bash
#
# This file is part of MinIO DirectPV
# Copyright (c) 2023 MinIO, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set -e -C -o pipefail
declare NODE
function delete_resource() {
resource="$1"
selector="directpv.min.io/node=${NODE}"
# unset the finalizers
kubectl get "${resource}" --selector="${selector}" -o custom-columns=NAME:.metadata.name --no-headers | while read -r name; do
kubectl patch "${resource}" "${name}" -p '{"metadata":{"finalizers":null}}' --type=merge
done
# delete the objects
kubectl delete "${resource}" --selector="${selector}" --ignore-not-found=true
}
function init() {
if [[ $# -ne 1 ]]; then
cat <<EOF
usage: remove-node.sh <NODE>
This script forcefully removes all the DirectPV resources from the node.
CAUTION: Remove operation is irreversible and may incur data loss if not used cautiously.
EOF
exit 255
fi
if ! which kubectl >/dev/null 2>&1; then
echo "kubectl not found; please install"
exit 255
fi
NODE="$1"
if kubectl get --ignore-not-found=true csinode "${NODE}" -o go-template='{{range .spec.drivers}}{{if eq .name "directpv-min-io"}}{{.name}}{{break}}{{end}}{{end}}' | grep -q .; then
echo "node ${NODE} is still in use; remove node ${NODE} from DirectPV DaemonSet and try again"
exit 255
fi
}
function main() {
delete_resource directpvvolumes
delete_resource directpvdrives
delete_resource directpvinitrequests
kubectl delete directpvnode "${NODE}" --ignore-not-found=true
}
init "$@"
main "$@"
create-storage-class.sh
Use the following script to create a new DirectPV storage class.
To use the script, use the following format:
create-storage-class.sh [new-storage-class-name] '[drive label]'
#!/usr/bin/env bash
#
# This file is part of MinIO DirectPV
# Copyright (c) 2023 MinIO, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set -e -C -o pipefail
declare NAME
declare -a DRIVE_LABELS
function init() {
if [[ $# -lt 2 ]]; then
cat <<EOF
USAGE:
create-storage-class.sh <NAME> <DRIVE-LABELS> ...
ARGUMENTS:
NAME new storage class name.
DRIVE-LABELS drive labels to be attached.
EXAMPLE:
# Create new storage class 'fast-tier-storage' with drive labels 'directpv.min.io/tier: fast'
$ create-storage-class.sh fast-tier-storage 'directpv.min.io/tier: fast'
# Create new storage class with more than one drive label
$ create-storage-class.sh fast-tier-unique 'directpv.min.io/tier: fast' 'directpv.min.io/volume-claim-id: bcea279a-df70-4d23-be41-9490f9933004'
EOF
exit 255
fi
NAME="$1"
shift
DRIVE_LABELS=( "$@" )
for val in "${DRIVE_LABELS[@]}"; do
if ! [[ "${val}" =~ ^directpv.min.io/.* ]]; then
echo "invalid label ${val}; label must start with 'directpv.min.io/'"
exit 255
fi
if [[ "${val}" =~ ^directpv.min.io/volume-claim-id:.* ]] && ! [[ "${val#directpv.min.io/volume-claim-id: }" =~ ^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$ ]]; then
echo "invalid volume-claim-id value; the value must be UUID as textual representation mentioned in https://en.wikipedia.org/wiki/Universally_unique_identifier#Textual_representation"
exit 255
fi
done
if ! which kubectl >/dev/null 2>&1; then
echo "kubectl not found; please install"
exit 255
fi
}
function main() {
kubectl apply -f - <<EOF
allowVolumeExpansion: true
allowedTopologies:
- matchLabelExpressions:
- key: directpv.min.io/identity
values:
- directpv-min-io
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
finalizers:
- foregroundDeletion
labels:
application-name: directpv.min.io
application-type: CSIDriver
directpv.min.io/created-by: kubectl-directpv
directpv.min.io/version: v1beta1
name: ${NAME}
parameters:
fstype: xfs
$(printf ' %s\n' "${DRIVE_LABELS[@]}")
provisioner: directpv-min-io
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
EOF
}
init "$@"
main "$@"
Repair faulty drives
#!/usr/bin/env bash
This file is part of MinIO DirectPV
Copyright (c) 2024 MinIO, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
http://www.gnu.org/licenses/.
along with this program. If not, seeThis script repairs faulty drives
set -e
ME=$(basename “$0”); export ME
declare -a drive_ids
usage: is_uuid
function is_uuid() { [[ “$1” =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] }
usage: get_suspend_value
function get_suspend_value() {
# shellcheck disable=SC2016
kubectl get directpvvolumes “${1}”
-o go-template=’{{range $k,$v := .metadata.labels}}{{if eq $k “directpv.min.io/suspend”}}{{$v}}{{end}}{{end}}'
}
usage: is_suspended
function is_suspended() { value=$(get_suspend_value “${1}”) [[ “${value,,}” = “true” ]] }
usage: get_volumes
function get_volumes() {
kubectl get directpvvolumes
–selector=“directpv.min.io/drive=${1}”
-o go-template=’{{range .items}}{{.metadata.name}}{{ " " | print }}{{end}}'
}
usage: get_pod_name
function get_pod_name() {
# shellcheck disable=SC2016
kubectl get directpvvolumes “${1}”
-o go-template=’{{range $k,$v := .metadata.labels}}{{if eq $k “directpv.min.io/pod.name”}}{{$v}}{{end}}{{end}}'
}
usage: get_pod_namespace
function get_pod_namespace() {
# shellcheck disable=SC2016
kubectl get directpvvolumes “${1}”
-o go-template=’{{range $k,$v := .metadata.labels}}{{if eq $k “directpv.min.io/pod.namespace”}}{{$v}}{{end}}{{end}}'
}
function init() { if [[ $# -eq 0 ]]; then cat «EOF NAME: ${ME} - This script repairs faulty drives. USAGE: ${ME} … ARGUMENTS: DRIVE-ID Faulty drive ID. EXAMPLE:
Repair drive af3b8b4c-73b4-4a74-84b7-1ec30492a6f0.
$ ${ME} af3b8b4c-73b4-4a74-84b7-1ec30492a6f0 EOF exit 255 fi
if ! which kubectl >/dev/null 2>&1; then
echo "kubectl not found; please install"
exit 255
fi
if ! kubectl directpv --version >/dev/null 2>&1; then
echo "kubectl directpv not found; please install"
exit 255
fi
for drive in "$@"; do
if ! is_uuid "${drive}"; then
echo "invalid drive ID ${drive}"
exit 255
fi
if [[ ! ${drive_ids[*]} =~ ${drive} ]]; then
drive_ids+=( "${drive}" )
fi
done
}
usage: repair
function repair() { drive_id="$1"
pods_deleted=true
if ! is_suspended "${drive_id}"; then
kubectl directpv suspend "${drive_id}"
# shellcheck disable=SC2207
volumes=( $(get_volumes "${drive_id}") )
for volume in "${volumes[@]}"; do
pod_name=$(get_pod_name "${volume}")
pod_namespace=$(get_pod_namespace "${volume}")
if ! kubectl delete pod "${pod_name}" --namespace "${pod_namespace}"; then
echo "unable to delete pod '${pod_name}' using volume '${volume}'; please delete the pod manually"
pods_deleted=false
fi
done
else
echo "drive ${drive_id} already suspended"
fi
if [ "${pods_deleted}" == "true" ]; then
kubectl directpv repair "${drive_id}"
else
echo "delete pods manually and retry again for drive ${drive_id}"
fi
}
function main() { for drive in “${drive_ids[@]}”; do repair “${drive}” done }
init “$@” main “$@”