Skip to content

Commit 7a0de75

Browse files
authored
Merge pull request #248 from pohly/storage-capacity
Storage capacity
2 parents 4c420f3 + 65e48f2 commit 7a0de75

17 files changed

+963
-232
lines changed

cmd/hostpathplugin/main.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ var (
3636
ephemeral = flag.Bool("ephemeral", false, "publish volumes in ephemeral mode even if kubelet did not ask for it (only needed for Kubernetes 1.15)")
3737
maxVolumesPerNode = flag.Int64("maxvolumespernode", 0, "limit of volumes per node")
3838
showVersion = flag.Bool("version", false, "Show version.")
39+
capacity = func() hostpath.Capacity {
40+
c := hostpath.Capacity{}
41+
flag.Var(c, "capacity", "Simulate storage capacity. The parameter is <kind>=<quantity> where <kind> is the value of a 'kind' storage class parameter and <quantity> is the total amount of bytes for that kind. The flag may be used multiple times to configure different kinds.")
42+
return c
43+
}()
3944
// Set by the build process
4045
version = ""
4146
)
@@ -53,12 +58,7 @@ func main() {
5358
fmt.Fprintln(os.Stderr, "Deprecation warning: The ephemeral flag is deprecated and should only be used when deploying on Kubernetes 1.15. It will be removed in the future.")
5459
}
5560

56-
handle()
57-
os.Exit(0)
58-
}
59-
60-
func handle() {
61-
driver, err := hostpath.NewHostPathDriver(*driverName, *nodeID, *endpoint, *ephemeral, *maxVolumesPerNode, version)
61+
driver, err := hostpath.NewHostPathDriver(*driverName, *nodeID, *endpoint, *ephemeral, *maxVolumesPerNode, version, capacity)
6262
if err != nil {
6363
fmt.Printf("Failed to initialize driver: %s", err.Error())
6464
os.Exit(1)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
This deployment is meant for Kubernetes clusters with
2+
CSIStorageCapacity enabled. It deploys the hostpath driver on each
3+
node, using distributed provisioning, and configures it so that it has
4+
10Gi of "fast" storage and 100Gi of "slow" storage.
5+
6+
The "kind" storage class parameter can selected between the two. If
7+
not set, an arbitrary kind with enough capacity is picked.
8+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This example Pod definition demonstrates
2+
# how to use generic ephemeral inline volumes
3+
# with a hostpath storage class.
4+
kind: Pod
5+
apiVersion: v1
6+
metadata:
7+
name: my-csi-app-inline-volume
8+
spec:
9+
containers:
10+
- name: my-frontend
11+
image: k8s.gcr.io/pause
12+
volumeMounts:
13+
- mountPath: "/data"
14+
name: my-csi-volume
15+
volumes:
16+
- name: my-csi-volume
17+
ephemeral:
18+
volumeClaimTemplate:
19+
spec:
20+
accessModes:
21+
- ReadWriteOnce
22+
resources:
23+
requests:
24+
storage: 4Gi
25+
storageClassName: csi-hostpath-fast
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env bash
2+
3+
# This script captures the steps required to successfully
4+
# deploy the hostpath plugin driver. This should be considered
5+
# authoritative and all updates for this process should be
6+
# done here and referenced elsewhere.
7+
8+
# The script assumes that kubectl is available on the OS path
9+
# where it is executed.
10+
11+
set -e
12+
set -o pipefail
13+
14+
BASE_DIR=$(dirname "$0")
15+
16+
# If set, the following env variables override image registry and/or tag for each of the images.
17+
# They are named after the image name, with hyphen replaced by underscore and in upper case.
18+
#
19+
# - CSI_ATTACHER_REGISTRY
20+
# - CSI_ATTACHER_TAG
21+
# - CSI_NODE_DRIVER_REGISTRAR_REGISTRY
22+
# - CSI_NODE_DRIVER_REGISTRAR_TAG
23+
# - CSI_PROVISIONER_REGISTRY
24+
# - CSI_PROVISIONER_TAG
25+
# - CSI_SNAPSHOTTER_REGISTRY
26+
# - CSI_SNAPSHOTTER_TAG
27+
# - HOSTPATHPLUGIN_REGISTRY
28+
# - HOSTPATHPLUGIN_TAG
29+
#
30+
# Alternatively, it is possible to override all registries or tags with:
31+
# - IMAGE_REGISTRY
32+
# - IMAGE_TAG
33+
# These are used as fallback when the more specific variables are unset or empty.
34+
#
35+
# IMAGE_TAG=canary is ignored for images that are blacklisted in the
36+
# deployment's optional canary-blacklist.txt file. This is meant for
37+
# images which have known API breakages and thus cannot work in those
38+
# deployments anymore. That text file must have the name of the blacklisted
39+
# image on a line by itself, other lines are ignored. Example:
40+
#
41+
# # The following canary images are known to be incompatible with this
42+
# # deployment:
43+
# csi-snapshotter
44+
#
45+
# Beware that the .yaml files do not have "imagePullPolicy: Always". That means that
46+
# also the "canary" images will only be pulled once. This is good for testing
47+
# (starting a pod multiple times will always run with the same canary image), but
48+
# implies that refreshing that image has to be done manually.
49+
#
50+
# As a special case, 'none' as registry removes the registry name.
51+
52+
# The default is to use the RBAC rules that match the image that is
53+
# being used, also in the case that the image gets overridden. This
54+
# way if there are breaking changes in the RBAC rules, the deployment
55+
# will continue to work.
56+
#
57+
# However, such breaking changes should be rare and only occur when updating
58+
# to a new major version of a sidecar. Nonetheless, to allow testing the scenario
59+
# where the image gets overridden but not the RBAC rules, updating the RBAC
60+
# rules can be disabled.
61+
: ${UPDATE_RBAC_RULES:=true}
62+
function rbac_version () {
63+
yaml="$1"
64+
image="$2"
65+
update_rbac="$3"
66+
67+
# get version from `image: quay.io/k8scsi/csi-attacher:v1.0.1`, ignoring comments
68+
version="$(sed -e 's/ *#.*$//' "$yaml" | grep "image:.*$image" | sed -e 's/ *#.*//' -e 's/.*://')"
69+
70+
if $update_rbac; then
71+
# apply overrides
72+
varname=$(echo $image | tr - _ | tr a-z A-Z)
73+
eval version=\${${varname}_TAG:-\${IMAGE_TAG:-\$version}}
74+
fi
75+
76+
# When using canary images, we have to assume that the
77+
# canary images were built from the corresponding branch.
78+
case "$version" in canary) version=master;;
79+
*-canary) version="$(echo "$version" | sed -e 's/\(.*\)-canary/release-\1/')";;
80+
esac
81+
82+
echo "$version"
83+
}
84+
85+
# version_gt returns true if arg1 is greater than arg2.
86+
#
87+
# This function expects versions to be one of the following formats:
88+
# X.Y.Z, release-X.Y.Z, vX.Y.Z
89+
#
90+
# where X,Y, and Z are any number.
91+
#
92+
# Partial versions (1.2, release-1.2) work as well.
93+
# The follow substrings are stripped before version comparison:
94+
# - "v"
95+
# - "release-"
96+
#
97+
# Usage:
98+
# version_gt release-1.3 v1.2.0 (returns true)
99+
# version_gt v1.1.1 v1.2.0 (returns false)
100+
# version_gt 1.1.1 v1.2.0 (returns false)
101+
# version_gt 1.3.1 v1.2.0 (returns true)
102+
# version_gt 1.1.1 release-1.2.0 (returns false)
103+
# version_gt 1.2.0 1.2.2 (returns false)
104+
function version_gt() {
105+
versions=$(for ver in "$@"; do ver=${ver#release-}; ver=${ver#kubernetes-}; echo ${ver#v}; done)
106+
greaterVersion=${1#"release-"};
107+
greaterVersion=${greaterVersion#"kubernetes-"};
108+
greaterVersion=${greaterVersion#"v"};
109+
test "$(printf '%s' "$versions" | sort -V | head -n 1)" != "$greaterVersion"
110+
}
111+
112+
113+
CSI_PROVISIONER_RBAC_YAML="https://raw.githubusercontent.com/kubernetes-csi/external-provisioner/$(rbac_version "${BASE_DIR}/hostpath/csi-hostpath-plugin.yaml" csi-provisioner false)/deploy/kubernetes/rbac.yaml"
114+
: ${CSI_PROVISIONER_RBAC:=https://raw.githubusercontent.com/kubernetes-csi/external-provisioner/$(rbac_version "${BASE_DIR}/hostpath/csi-hostpath-plugin.yaml" csi-provisioner "${UPDATE_RBAC_RULES}")/deploy/kubernetes/rbac.yaml}
115+
116+
# Some images are not affected by *_REGISTRY/*_TAG and IMAGE_* variables.
117+
# The default is to update unless explicitly excluded.
118+
update_image () {
119+
case "$1" in socat) return 1;; esac
120+
}
121+
122+
run () {
123+
echo "$@" >&2
124+
"$@"
125+
}
126+
127+
# rbac rules
128+
echo "applying RBAC rules"
129+
for component in CSI_PROVISIONER; do
130+
eval current="\${${component}_RBAC}"
131+
eval original="\${${component}_RBAC_YAML}"
132+
if [ "$current" != "$original" ]; then
133+
echo "Using non-default RBAC rules for $component. Changes from $original to $current are:"
134+
diff -c <(wget --quiet -O - "$original") <(if [[ "$current" =~ ^http ]]; then wget --quiet -O - "$current"; else cat "$current"; fi) || true
135+
fi
136+
run kubectl apply -f "${current}"
137+
done
138+
139+
if kubectl get csistoragecapacities 2>&1 | grep "the server doesn't have a resource type"; then
140+
have_csistoragecapacity=false
141+
else
142+
have_csistoragecapacity=true
143+
fi
144+
145+
# deploy hostpath plugin and registrar sidecar
146+
echo "deploying hostpath components"
147+
for i in $(ls ${BASE_DIR}/hostpath/*.yaml | sort); do
148+
echo " $i"
149+
modified="$(cat "$i" | while IFS= read -r line; do
150+
nocomments="$(echo "$line" | sed -e 's/ *#.*$//')"
151+
if echo "$nocomments" | grep -q '^[[:space:]]*image:[[:space:]]*'; then
152+
# Split 'image: quay.io/k8scsi/csi-attacher:v1.0.1'
153+
# into image (quay.io/k8scsi/csi-attacher:v1.0.1),
154+
# registry (quay.io/k8scsi),
155+
# name (csi-attacher),
156+
# tag (v1.0.1).
157+
image=$(echo "$nocomments" | sed -e 's;.*image:[[:space:]]*;;')
158+
registry=$(echo "$image" | sed -e 's;\(.*\)/.*;\1;')
159+
name=$(echo "$image" | sed -e 's;.*/\([^:]*\).*;\1;')
160+
tag=$(echo "$image" | sed -e 's;.*:;;')
161+
162+
# Variables are with underscores and upper case.
163+
varname=$(echo $name | tr - _ | tr a-z A-Z)
164+
165+
# Now replace registry and/or tag, if set as env variables.
166+
# If not set, the replacement is the same as the original value.
167+
# Only do this for the images which are meant to be configurable.
168+
if update_image "$name"; then
169+
prefix=$(eval echo \${${varname}_REGISTRY:-${IMAGE_REGISTRY:-${registry}}}/ | sed -e 's;none/;;')
170+
if [ "$IMAGE_TAG" = "canary" ] &&
171+
[ -f ${BASE_DIR}/canary-blacklist.txt ] &&
172+
grep -q "^$name\$" ${BASE_DIR}/canary-blacklist.txt; then
173+
# Ignore IMAGE_TAG=canary for this particular image because its
174+
# canary image is blacklisted in the deployment blacklist.
175+
suffix=$(eval echo :\${${varname}_TAG:-${tag}})
176+
else
177+
suffix=$(eval echo :\${${varname}_TAG:-${IMAGE_TAG:-${tag}}})
178+
fi
179+
line="$(echo "$nocomments" | sed -e "s;$image;${prefix}${name}${suffix};")"
180+
fi
181+
echo " using $line" >&2
182+
fi
183+
if ! $have_csistoragecapacity; then
184+
line="$(echo "$line" | grep -v -e 'storageCapacity: true' -e '--enable-capacity')"
185+
fi
186+
echo "$line"
187+
done)"
188+
if ! echo "$modified" | kubectl apply -f -; then
189+
echo "modified version of $i:"
190+
echo "$modified"
191+
exit 1
192+
fi
193+
done
194+
195+
wait_for_daemonset () {
196+
retries=10
197+
while [ $retries -ge 0 ]; do
198+
ready=$(kubectl get -n $1 daemonset $2 -o jsonpath="{.status.numberReady}")
199+
required=$(kubectl get -n $1 daemonset $2 -o jsonpath="{.status.desiredNumberScheduled}")
200+
if [ $ready -gt 0 ] && [ $ready -eq $required ]; then
201+
return 0
202+
fi
203+
retries=$((retries - 1))
204+
sleep 3
205+
done
206+
return 1
207+
}
208+
209+
210+
# Wait until the DaemonSet is running on all nodes.
211+
if ! wait_for_daemonset default csi-hostpathplugin; then
212+
echo "driver not ready"
213+
kubectl describe daemonsets/csi-hostpathplugin
214+
exit 1
215+
fi
216+
217+
# Create a test driver configuration in the place where the prow job
218+
# expects it?
219+
if [ "${CSI_PROW_TEST_DRIVER}" ]; then
220+
cp "${BASE_DIR}/test-driver.yaml" "${CSI_PROW_TEST_DRIVER}"
221+
fi
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: storage.k8s.io/v1
2+
kind: CSIDriver
3+
metadata:
4+
name: hostpath.csi.k8s.io
5+
spec:
6+
# Supports persistent and ephemeral inline volumes.
7+
volumeLifecycleModes:
8+
- Persistent
9+
- Ephemeral
10+
# To determine at runtime which mode a volume uses, pod info and its
11+
# "csi.storage.k8s.io/ephemeral" entry are needed.
12+
podInfoOnMount: true
13+
# No attacher needed.
14+
attachRequired: false
15+
# alpha: opt into capacity-aware scheduling
16+
storageCapacity: true

0 commit comments

Comments
 (0)