Skip to content
Open
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
14 changes: 14 additions & 0 deletions charts/dgraph/templates/alpha/svc-headless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ spec:
- name: grpc-alpha-int
port: 7080
targetPort: 7080
## http-alpha (8080) and grpc-alpha (9080) are exposed here only when backups are
## enabled (backups.full.enabled or backups.incremental.enabled): the backup CronJobs
## are their consumer, addressing a single pinned pod (alpha-0) through this headless
## Service, and under a STRICT mTLS service mesh (e.g. Istio) the client sidecar only
## builds an mTLS route for ports the Service declares. Without 8080 here, the backup
## /admin login falls through to plaintext and Alpha's sidecar resets the connection.
{{- if or .Values.backups.full.enabled .Values.backups.incremental.enabled }}
- name: http-alpha
port: 8080
targetPort: 8080
- name: grpc-alpha
port: 9080
targetPort: 9080
{{- end }}
selector:
app: {{ template "dgraph.name" . }}
component: {{ .Values.alpha.name }}
Expand Down
120 changes: 69 additions & 51 deletions charts/dgraph/templates/backups/configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,69 @@ metadata:
data:
backup.sh: |
######
# get_token_rest - get accessJWT token with REST command for Dgraph 1.x
# require_json - validate a curl response before parsing it as JSON
# params:
# 1: body - the response body to validate
# 2: curl_status - exit status of the curl that produced the body
# 3: url - request URL, for the error message
# A failed connection through a service mesh (or any network error) returns a
# non-JSON body, e.g. Envoy's "upstream connect error ...", which the field
# extraction below cannot parse. Surface the curl status, the URL, and the raw
# body instead of failing silently with an empty token. Only bodies that fail
# validation are echoed, so a successful login response is never printed.
##########################
get_token_rest() {
JSON="{\"userid\": \"${USER}\", \"password\": \"${PASSWORD}\" }"
RESULT=$(
/usr/bin/curl --silent \
"${HEADERS[@]}" \
"${CERTOPTS[@]}" \
--request POST \
${ALPHA_HOST}:8080/login \
--data "${JSON}"
)

if grep -q errors <<< "$RESULT"; then
ERROR=$(grep -oP '(?<=message":")[^"]*' <<< $RESULT)
echo "ERROR: $ERROR"
require_json() {
BODY=${1}
CURL_STATUS=${2}
URL=${3}
if [[ "$CURL_STATUS" -ne 0 ]]; then
echo "ERROR: curl to ${URL} failed with exit ${CURL_STATUS}: ${BODY}" >&2
return 1
fi
if [[ -z "$BODY" ]]; then
echo "ERROR: empty response from ${URL}" >&2
return 1
fi
if ! jq -e . >/dev/null 2>&1 <<< "$BODY"; then
echo "ERROR: non-JSON response from ${URL}: ${BODY}" >&2
return 1
fi
}

grep -oP '(?<=accessJWT":")[^"]*' <<< "$RESULT"

######
# get_token_rest - get accessJWT token with REST command for Dgraph 1.x
##########################
get_token_rest() {
JSON=$(jq -n --arg userid "$USER" --arg password "$PASSWORD" '{userid: $userid, password: $password}')
CURL_STATUS=0
RESULT=$(
/usr/bin/curl --silent "${HEADERS[@]}" "${CERTOPTS[@]}" \
--request POST ${ALPHA_HOST}:8080/login --data "${JSON}"
) || CURL_STATUS=$?
require_json "$RESULT" "$CURL_STATUS" "${ALPHA_HOST}:8080/login" || return 1
ERROR=$(jq -r '.errors[0].message // empty' <<< "$RESULT")
if [[ -n "$ERROR" ]]; then echo "ERROR: $ERROR"; return 1; fi
TOKEN=$(jq -r '.data.accessJWT // empty' <<< "$RESULT")
[[ -n "$TOKEN" ]] || { echo "ERROR: could not parse accessJWT from /login response" >&2; return 1; }
echo "$TOKEN"
}

######
# get_token_graphql - get accessJWT token using GraphQL for Dgraph 20.03.1+
##########################
get_token_graphql() {
GQL="{\"query\": \"mutation { login(userId: \\\"${USER}\\\" password: \\\"${PASSWORD}\\\") { response { accessJWT } } }\"}"
GQL=$(jq -n --arg userId "$USER" --arg password "$PASSWORD" '{query: "mutation ($userId: String, $password: String) { login(userId: $userId, password: $password) { response { accessJWT } } }", variables: {userId: $userId, password: $password}}')
CURL_STATUS=0
RESULT=$(
/usr/bin/curl --silent \
"${HEADERS[@]}" \
"${CERTOPTS[@]}" \
--request POST \
${ALPHA_HOST}:8080/admin \
--data "${GQL}"
)

if grep -q errors <<< "$RESULT"; then
ERROR=$(grep -oP '(?<=message":")[^"]*' <<< $RESULT)
echo "ERROR: $ERROR"
return 1
fi

grep -oP '(?<=accessJWT":")[^"]*' <<< "$RESULT"

/usr/bin/curl --silent "${HEADERS[@]}" "${CERTOPTS[@]}" \
--request POST ${ALPHA_HOST}:8080/admin --data "${GQL}"
) || CURL_STATUS=$?
require_json "$RESULT" "$CURL_STATUS" "${ALPHA_HOST}:8080/admin" || return 1
ERROR=$(jq -r '.errors[0].message // empty' <<< "$RESULT")
if [[ -n "$ERROR" ]]; then echo "ERROR: $ERROR"; return 1; fi
TOKEN=$(jq -r '.data.login.response.accessJWT // empty' <<< "$RESULT")
[[ -n "$TOKEN" ]] || { echo "ERROR: could not parse accessJWT from /admin login response" >&2; return 1; }
echo "$TOKEN"
}

######
Expand All @@ -74,6 +92,8 @@ data:
CACERT_PATH=${CACERT_PATH:-""}
CLIENT_CERT_PATH=${CLIENT_CERT_PATH:-""}
CLIENT_KEY_PATH=${CLIENT_KEY_PATH:-""}
HEADERS=()
CERTOPTS=()

## user/password required for login
if [[ -z "$USER" || -z "$PASSWORD" ]]; then
Expand Down Expand Up @@ -125,6 +145,8 @@ data:
CACERT_PATH=${CACERT_PATH:-""}
CLIENT_CERT_PATH=${CLIENT_CERT_PATH:-""}
CLIENT_KEY_PATH=${CLIENT_KEY_PATH:-""}
HEADERS=()
CERTOPTS=()

API_TYPE=${API_TYPE:-"graphql"}

Expand Down Expand Up @@ -188,24 +210,22 @@ data:
backup_rest() {
URL_PATH="admin/backup?force_full=$FORCE_FULL"

CURL_STATUS=0
RESULT=$(/usr/bin/curl --silent \
"${HEADERS[@]}" \
"${CERTOPTS[@]}" \
--request POST \
${ALPHA_HOST}:8080/$URL_PATH \
--data "destination=$BACKUP_DESTINATION"
)

if grep -q errors <<< "$RESULT"; then
ERROR=$(grep -oP '(?<=message":")[^"]*' <<< $RESULT)
MESSAGE="ERROR: $ERROR"
if grep -q code <<< "$RESULT"; then
CODE=$(grep -oP '(?<=code":")[^"]*' <<< $RESULT)
echo "$MESSAGE REASON='$CODE'"
fi
) || CURL_STATUS=$?
require_json "$RESULT" "$CURL_STATUS" "${ALPHA_HOST}:8080/${URL_PATH}" || return 1

ERROR=$(jq -r '.errors[0].message // empty' <<< "$RESULT")
if [[ -n "$ERROR" ]]; then
CODE=$(jq -r '.errors[0].code // empty' <<< "$RESULT")
if [[ -n "$CODE" ]]; then echo "ERROR: $ERROR REASON='$CODE'"; else echo "ERROR: $ERROR"; fi
return 1
fi

echo $RESULT

}
Expand All @@ -216,20 +236,18 @@ data:
backup_graphql() {
GQL="{\"query\": \"mutation { backup(input: {destination: \\\"${BACKUP_DESTINATION}\\\" forceFull: $FORCE_FULL }) { response { message code } } }\"}"

CURL_STATUS=0
RESULT=$(/usr/bin/curl --silent \
"${HEADERS[@]}" \
"${CERTOPTS[@]}" \
--request POST \
$ALPHA_HOST:8080/admin \
--data "$GQL"
)

if grep -q errors <<< "$RESULT"; then
ERROR=$(grep -oP '(?<=message":")[^"]*' <<< $RESULT)
echo "ERROR: $ERROR"
return 1
fi
) || CURL_STATUS=$?
require_json "$RESULT" "$CURL_STATUS" "${ALPHA_HOST}:8080/admin" || return 1

ERROR=$(jq -r '.errors[0].message // empty' <<< "$RESULT")
if [[ -n "$ERROR" ]]; then echo "ERROR: $ERROR"; return 1; fi
echo $RESULT
}
{{- end }}
2 changes: 1 addition & 1 deletion charts/dgraph/templates/backups/cronjob-full.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ spec:
{{- end }}

{{- if .Values.alpha.acl.enabled }}
ACCESS_TOKEN=$(get_token {{ .Values.backups.admin.user }} $(cat /backup_secrets/backup_admin_password) $AUTH_TOKEN )
ACCESS_TOKEN=$(get_token "{{ .Values.backups.admin.user }}" "$(cat /backup_secrets/backup_admin_password)" "${AUTH_TOKEN:-}")
{{- end }}

## Full Backup with optional access and auth tokens
Expand Down
2 changes: 1 addition & 1 deletion charts/dgraph/templates/backups/cronjob-inc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ spec:
{{- end }}

{{- if .Values.alpha.acl.enabled }}
ACCESS_TOKEN=$(get_token {{ .Values.backups.admin.user }} $(cat /backup_secrets/backup_admin_password) $AUTH_TOKEN )
ACCESS_TOKEN=$(get_token "{{ .Values.backups.admin.user }}" "$(cat /backup_secrets/backup_admin_password)" "${AUTH_TOKEN:-}")
{{- end }}

## Incremental Backup with optional access and auth tokens
Expand Down