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
35 changes: 24 additions & 11 deletions internal/postgres/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,24 @@ func reloadCommand(
// descriptor gets closed and reopened to use the builtin `[ -nt` to check
// mtimes.
// - https://unix.stackexchange.com/a/407383
//
// In the manageAutogrowAnnotation function below, df is used to return the
// relevant volume size in Mebibytes. The 'read' variable gets the value from
// the '1M-blocks' output (second column) and the 'use' variable gets the value
// from the 'Use%' column (fifth column). This value is grabbed after stripping
// out the column headers (before the '\n') and then getting the respective
// value delimited by the white spaces by using the 'read -r' command.
// The underscores (_) discard fields and the variables store them. This allows
// for selective parsing of the provided lines. The percent value is stripped of
// the '%' and then used to determine if a expansion should be triggered by
// setting the calculated volume size using the 'size' variable.
script := fmt.Sprintf(`
# Parameters for curl when managing autogrow annotation.
APISERVER="https://kubernetes.default.svc"
SERVICEACCOUNT="/var/run/secrets/kubernetes.io/serviceaccount"
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
TOKEN=$(cat ${SERVICEACCOUNT}/token)
CACERT=${SERVICEACCOUNT}/ca.crt
NAMESPACE=$(cat "${SERVICEACCOUNT}/namespace")
TOKEN=$(cat "${SERVICEACCOUNT}/token")
CACERT="${SERVICEACCOUNT}/ca.crt"

# Manage autogrow annotation.
# Return size in Mebibytes.
Expand All @@ -313,27 +324,29 @@ manageAutogrowAnnotation() {
local trigger=$2
local maxGrow=$3

size=$(df --block-size=M /"${volume}" | awk 'FNR == 2 {print $2}')
use=$(df /"${volume}" | awk 'FNR == 2 {print $5}')
size=$(df --block-size=M /"${volume}")
read -r _ size _ <<< "${size#*$'\n'}"
use=$(df /"${volume}")
read -r _ _ _ _ use _ <<< "${use#*$'\n'}"
sizeInt="${size//M/}"
# Use the sed punctuation class, because the shell will not accept the percent sign in an expansion.
useInt=$(echo $use | sed 's/[[:punct:]]//g')
useInt=${use//[[:punct:]]/}
triggerExpansion="$((useInt > trigger))"
if [[ $triggerExpansion -eq 1 ]]; then
if [[ ${triggerExpansion} -eq 1 ]]; then
newSize="$(((sizeInt / 2)+sizeInt))"
# Only compare with maxGrow if it is set (not empty)
if [[ -n "$maxGrow" ]]; then
if [[ -n "${maxGrow}" ]]; then
# check to see how much we would normally grow
sizeDiff=$((newSize - sizeInt))

# Compare the size difference to the maxGrow; if it is greater, cap it to maxGrow
if [[ $sizeDiff -gt $maxGrow ]]; then
if [[ ${sizeDiff} -gt ${maxGrow} ]]; then
newSize=$((sizeInt + maxGrow))
fi
fi
newSizeMi="${newSize}Mi"
d='[{"op": "add", "path": "/metadata/annotations/suggested-'"${volume}"'-pvc-size", "value": "'"$newSizeMi"'"}]'
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "$d"
d='[{"op": "add", "path": "/metadata/annotations/suggested-'"${volume}"'-pvc-size", "value": "'"${newSizeMi}"'"}]'
curl --cacert "${CACERT}" --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "${d}"
fi
}

Expand Down
43 changes: 43 additions & 0 deletions internal/postgres/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import (
"time"

"gotest.tools/v3/assert"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"

"github.com/crunchydata/postgres-operator/internal/initialize"
"github.com/crunchydata/postgres-operator/internal/testing/cmp"
"github.com/crunchydata/postgres-operator/internal/testing/require"
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
Expand Down Expand Up @@ -600,3 +602,44 @@ EOF
chmod +x /tmp/pg_rewind_tde.sh`))
})
}

func TestReloadCommand(t *testing.T) {
shellcheck := require.ShellCheck(t)

pgdataSize := resource.MustParse("1Gi")
pgwalSize := resource.MustParse("2Gi")

command := reloadCommand(
"some-name",
&v1beta1.VolumeClaimSpecWithAutoGrow{
AutoGrow: &v1beta1.AutoGrowSpec{
Trigger: initialize.Int32(10),
MaxGrow: &pgdataSize,
},
},
&v1beta1.VolumeClaimSpecWithAutoGrow{
AutoGrow: &v1beta1.AutoGrowSpec{
Trigger: initialize.Int32(20),
MaxGrow: &pgwalSize,
},
},
)

// Expect a bash command with an inline script.
assert.DeepEqual(t, command[:3], []string{"bash", "-ceu", "--"})
assert.Assert(t, len(command) > 3)

// Write out that inline script.
dir := t.TempDir()
file := filepath.Join(dir, "script.bash")
assert.NilError(t, os.WriteFile(file, []byte(command[3]), 0o600))

// Expect shellcheck to be happy.
cmd := exec.CommandContext(t.Context(), shellcheck, "--enable=all", file)
output, err := cmd.CombinedOutput()
assert.NilError(t, err, "%q\n%s", cmd.Args, output)

assert.Assert(t, cmp.Contains(command[3], "manageAutogrowAnnotation \"pgdata\" \"10\" \"1024\""))
assert.Assert(t, cmp.Contains(command[3], "manageAutogrowAnnotation \"pgwal\" \"20\" \"2048\""))

}
24 changes: 13 additions & 11 deletions internal/postgres/reconcile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ containers:
# Parameters for curl when managing autogrow annotation.
APISERVER="https://kubernetes.default.svc"
SERVICEACCOUNT="/var/run/secrets/kubernetes.io/serviceaccount"
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
TOKEN=$(cat ${SERVICEACCOUNT}/token)
CACERT=${SERVICEACCOUNT}/ca.crt
NAMESPACE=$(cat "${SERVICEACCOUNT}/namespace")
TOKEN=$(cat "${SERVICEACCOUNT}/token")
CACERT="${SERVICEACCOUNT}/ca.crt"

# Manage autogrow annotation.
# Return size in Mebibytes.
Expand All @@ -184,27 +184,29 @@ containers:
local trigger=$2
local maxGrow=$3

size=$(df --block-size=M /"${volume}" | awk 'FNR == 2 {print $2}')
use=$(df /"${volume}" | awk 'FNR == 2 {print $5}')
size=$(df --block-size=M /"${volume}")
read -r _ size _ <<< "${size#*$'\n'}"
use=$(df /"${volume}")
read -r _ _ _ _ use _ <<< "${use#*$'\n'}"
sizeInt="${size//M/}"
# Use the sed punctuation class, because the shell will not accept the percent sign in an expansion.
useInt=$(echo $use | sed 's/[[:punct:]]//g')
useInt=${use//[[:punct:]]/}
triggerExpansion="$((useInt > trigger))"
if [[ $triggerExpansion -eq 1 ]]; then
if [[ ${triggerExpansion} -eq 1 ]]; then
newSize="$(((sizeInt / 2)+sizeInt))"
# Only compare with maxGrow if it is set (not empty)
if [[ -n "$maxGrow" ]]; then
if [[ -n "${maxGrow}" ]]; then
# check to see how much we would normally grow
sizeDiff=$((newSize - sizeInt))

# Compare the size difference to the maxGrow; if it is greater, cap it to maxGrow
if [[ $sizeDiff -gt $maxGrow ]]; then
if [[ ${sizeDiff} -gt ${maxGrow} ]]; then
newSize=$((sizeInt + maxGrow))
fi
fi
newSizeMi="${newSize}Mi"
d='[{"op": "add", "path": "/metadata/annotations/suggested-'"${volume}"'-pvc-size", "value": "'"$newSizeMi"'"}]'
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "$d"
d='[{"op": "add", "path": "/metadata/annotations/suggested-'"${volume}"'-pvc-size", "value": "'"${newSizeMi}"'"}]'
curl --cacert "${CACERT}" --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "${d}"
fi
}

Expand Down
Loading