Skip to content

Commit

Permalink
test(RHIDP-460): update rhdh-setup and add search-catalog scenario (#19)
Browse files Browse the repository at this point in the history
* Patch creates users, groups, api and components

This patch introduces two new environment variables, that need to be set for deploy.sh script to run, GITHUB_USER and GITHUB_REPO. They will be used to host the API and Components for backstage.
Example:
GITHUB_USER=yogananth-subramanian
GITHUB_REPO=https://github.com/yogananth-subramanian/test1.git

It also introduces 5 more variables to modify deploy.sh behavior and create backstage objects.

- PRE_LOAD_DB, default set to true, if set, users and groups created before backstage_install or else they would be created after.
- BACKSTAGE_USER_COUNT, number of users in keycloak to create 
- GROUP_COUNT, number of groups in keycloak to create 
- API_COUNT, number of api object to create
- COMPONENT_COUNT, number of components to create

* test(RHIDP-460): update rhdh-setup and add search-catalog scenario

Signed-off-by: Pavel Macík <[email protected]>

---------

Signed-off-by: Pavel Macík <[email protected]>
Co-authored-by: yogananth-subramanian <[email protected]>
  • Loading branch information
pmacik and yogananth-subramanian authored Dec 8, 2023
1 parent 13415d3 commit 468ce13
Show file tree
Hide file tree
Showing 17 changed files with 686 additions and 118 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/pr-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,3 @@ jobs:

- name: Run linters
run: make lint

- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
**/.tmp/*
.venv
.vscode
.rhdh-setup.git*
benchmark-scenario
benchmark-before
benchmark-after
load-test.log
shellcheck
shellcheck
47 changes: 30 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ export DURATION ?= 1m
# Used to set --spawn-rate option of locust CLI (Rate to spawn users at (users per second)). See https://docs.locust.io/en/stable/configuration.html#command-line-options for details
export SPAWN_RATE ?= 20

# RHDH image to deploy
export RHDH_IMAGE_REGISTRY ?= quay.io
export RHDH_IMAGE_REPO ?= rhdh/rhdh-hub-rhel9
export RHDH_IMAGE_TAG ?= 1.0-162
# RHDH image to deploy. Uncomment and set to override RHDH image to deploy and test.
export RHDH_IMAGE_REGISTRY ?=
export RHDH_IMAGE_REPO ?=
export RHDH_IMAGE_TAG ?=

# RHDH Helm chart to deploy
export RHDH_NAMESPACE ?= rhdh-performance
export RHDH_HELM_REPO ?= https://gist.githubusercontent.com/nickboldt/a8483eb244f9c4286798e85accaa70af/raw/
export RHDH_HELM_REPO ?= https://gist.githubusercontent.com/rhdh-bot/63cef5cb6285889527bd6a67c0e1c2a9/raw
export RHDH_HELM_CHART ?= developer-hub
export RHDH_HELM_CHART_VERSION ?=
export RHDH_HELM_RELEASE_NAME ?= rhdh

# RHDH horizontal scaling
Expand All @@ -35,6 +36,9 @@ export RHDH_KEYCLOAK_REPLICAS ?= 1
# python's venv base dir relative to the root of the repository
PYTHON_VENV=.venv

# Local directory to store temporary files
export TMP_DIR=$(shell readlink -m .tmp)

# Name of the namespace to install locust operator as well as to run Pods of master and workers.
LOCUST_NAMESPACE=locust-operator

Expand Down Expand Up @@ -64,12 +68,17 @@ namespace:
## Deploy RHDH
.PHONY: deploy-rhdh
deploy-rhdh:
./ci-scripts/setup.sh
cd ./ci-scripts/rhdh-setup/; ./deploy.sh -i

## Create users, groups and objects such as components and APIs in RHDH
.PHONY: populate-rhdh
populate-rhdh:
cd ./ci-scripts/rhdh-setup/; ./deploy.sh -c

## Undeploy RHDH
.PHONY: undeploy-rhdh
undeploy-rhdh:
./ci-scripts/rhdh-setup/deploy.sh -d
cd ./ci-scripts/rhdh-setup/; ./deploy.sh -d

## === Locust Operator ===

Expand All @@ -93,18 +102,12 @@ undeploy-locust: clean
@kubectl delete namespace $(LOCUST_NAMESPACE) --wait
@helm repo remove $(LOCUST_OPERATOR_REPO)

## Add docker.io token to default-dockercfg-* Secret to avoid pull rate limits from docker.io
## Run `make add-dockerio DOCKERIO_TOKEN=...`
.PHONY: add-dockerio
add-dockerio: namespace
@TOKEN=$(DOCKERIO_TOKEN) NAMESPACE=$(LOCUST_NAMESPACE) ./add-dockercfg-docker.io.sh

## === Testing ===

## Remove test related resources from cluster
## Run `make clean SCENARIO=...` to clean a specific scenario
.PHONY: clean
clean:
## Run `make clean-test SCENARIO=...` to clean a specific scenario from cluster
.PHONY: clean-test
clean-test:
kubectl delete --namespace $(LOCUST_NAMESPACE) cm locust.$(SCENARIO) --ignore-not-found --wait
kubectl delete --namespace $(LOCUST_NAMESPACE) locusttests.locust.io $(SCENARIO).test --ignore-not-found --wait || true

Expand Down Expand Up @@ -132,12 +135,17 @@ shellcheck:
## Run all linters
.PHONY: lint
lint: shellcheck
shellcheck $$(find -name '*.sh')

## === CI ===

## Run the load test in CI end to end
.PHONY: ci-run
ci-run: setup-venv deploy-locust add-dockerio test
ci-run: setup-venv deploy-locust test

## Deploy and populate RHDH in CI end to end
.PHONY: ci-deploy
ci-deploy: clean namespace deploy-rhdh

## === Maintanence ===

Expand All @@ -149,6 +157,11 @@ update-locust-images:
skopeo copy --src-no-creds docker://docker.io/containersol/locust_exporter:latest docker://quay.io/backstage-performance/locust_exporter:latest
skopeo copy --src-no-creds docker://docker.io/lotest/locust-k8s-operator:latest docker://quay.io/backstage-performance/locust-k8s-operator:latest

## Clean local resources
.PHONY: clean
clean:
rm -rvf *.log benchmark-* shellcheck ci-scripts/rhdh-setup/.tmp $(TMP_DIR)

## === Help ===

## Print help message for all Makefile targets
Expand Down
8 changes: 0 additions & 8 deletions add-dockercfg-docker.io.sh

This file was deleted.

39 changes: 32 additions & 7 deletions ci-scripts/collect-results.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,43 @@ set -o nounset
set -o errexit
set -o pipefail

echo -e "\n === Collecting test results and metrics ===\n"

ARTIFACT_DIR=${ARTIFACT_DIR:-artifacts}
mkdir -p "${ARTIFACT_DIR}"

monitoring_collection_data=$ARTIFACT_DIR/benchmark.json
monitoring_collection_log=$ARTIFACT_DIR/monitoring-collection.log
monitoring_collection_dir=$ARTIFACT_DIR/monitoring-collection-raw-data-dir
mkdir -p "$monitoring_collection_dir"

cp -vf load-test.log $ARTIFACT_DIR/load-test.log
try_gather_file() {
if [ -f "$1" ]; then
cp -vf "$1" "${2:-$ARTIFACT_DIR}"
else
echo "WARNING: Tried to gather $1 but the file was not found!"
fi
}

try_gather_dir() {
if [ -d "$1" ]; then
cp -rvf "$1" "${2:-$ARTIFACT_DIR}"
else
echo "WARNING: Tried to gather $1 but the directory was not found!"
fi
}

try_gather_file ./.tmp/backstage.url
try_gather_file ./.tmp/keycloak.url
try_gather_file ./.tmp/chart-values.yaml
try_gather_file load-test.log

PYTHON_VENV_DIR=.venv

echo "$(date --utc -Ins) Setting up tool to collect monitoring data"
python3 -m venv $PYTHON_VENV_DIR
set +u
# shellcheck disable=SC1090,SC1091
source $PYTHON_VENV_DIR/bin/activate
set -u
python3 -m pip install --quiet -U pip
Expand All @@ -27,20 +51,21 @@ set -u

echo "$(date --utc -Ins) Collecting monitoring data"
set +u
# shellcheck disable=SC1090,SC1091
source $PYTHON_VENV_DIR/bin/activate
set -u
mstart=$(date --utc --date "$(cat benchmark-before)" --iso-8601=seconds)
mend=$(date --utc --date "$(cat benchmark-after)" --iso-8601=seconds)
mhost=$(kubectl -n openshift-monitoring get route -l app.kubernetes.io/name=thanos-query -o json | jq --raw-output '.items[0].spec.host')
mversion=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' scenarios/$(cat benchmark-scenario).py)
mversion=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' "scenarios/$(cat benchmark-scenario).py")
status_data.py \
--status-data-file "$monitoring_collection_data" \
--set \
results.started="$(cat benchmark-before)" \
results.ended="$(cat benchmark-after)" \
name="RHDH load test $(cat benchmark-scenario)" \
metadata.scenario.name="$(cat benchmark-scenario)" \
metadata.scenario.version="$mversion" \
results.started="$(cat benchmark-before)" \
results.ended="$(cat benchmark-after)" \
name="RHDH load test $(cat benchmark-scenario)" \
metadata.scenario.name="$(cat benchmark-scenario)" \
metadata.scenario.version="$mversion" \
-d &>"$monitoring_collection_log"
status_data.py \
--status-data-file "$monitoring_collection_data" \
Expand Down
1 change: 1 addition & 0 deletions ci-scripts/rhdh-setup/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
nohup.out
app-config.yaml
config.yaml
11 changes: 9 additions & 2 deletions ci-scripts/rhdh-setup/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# rhdh-setup
Run `./deploy.sh` to setup backstage with keycloak.
The script expects `QUAY_TOKEN` and `GITHUB_TOKEN` to be set.
Run `./deploy.sh -i` to install backstage with keycloak.

The script expects follwoing environmental variables to be set:
* `QUAY_TOKEN`
* `GITHUB_TOKEN`
* `GITHUB_USER`
* `GITHUB_REPO`

Run with `-r` to delete backstage and redeploy again `./deploy.sh -r`. This is used to syc up users and groups from keycloak.

Run with `-d` to delete backstage only.

Run with `-c` to create objects (Users, Groups, Components and APIs).
156 changes: 156 additions & 0 deletions ci-scripts/rhdh-setup/create_resource.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/bin/bash

export TMP_DIR WORKDIR

TMP_DIR=${TMP_DIR:-$(readlink -m .tmp)}
mkdir -p "$TMP_DIR"
WORKDIR=$(readlink -m .)

kc_lockfile="$TMP_DIR/kc.lockfile"

keycloak_url() {
f="$TMP_DIR/keycloak.url"
exec 4>"$kc_lockfile"
flock 4 || {
echo "Failed to acquire lock"
exit 1
}

if [ ! -f "$f" ]; then
echo -n "https://$(oc get routes keycloak -n "${RHDH_NAMESPACE}" -o jsonpath='{.spec.host}')" >"$f"
fi
cat "$f"
set +x
}

bs_lockfile="$TMP_DIR/bs.lockfile"

backstage_url() {
f="$TMP_DIR/backstage.url"
exec 5>"$bs_lockfile"
flock 5 || {
echo "Failed to acquire lock"
exit 1
}
if [ ! -f "$f" ]; then
echo -n "https://$(oc get routes "${RHDH_HELM_RELEASE_NAME}-developer-hub" -n "${RHDH_NAMESPACE}" -o jsonpath='{.spec.host}')" >"$f"
fi
flock -u 5
cat "$f"
}

create_per_grp() {
varname=$2
obj_count=${!varname}
if [[ -z ${!varname} ]]; then
echo "$varname is not set: Skipping $1 "
exit 1
fi
local iter_count mod
iter_count=$(echo "(${obj_count}/${GROUP_COUNT})" | bc)
mod=$(echo "(${obj_count}%${GROUP_COUNT})" | bc)

if [[ ! ${mod} -eq 0 ]]; then
iter_count=$(echo "${iter_count}+1" | bc)
fi
indx=0
for _ in $(seq 1 "${iter_count}"); do
for g in $(seq 1 "${GROUP_COUNT}"); do
indx=$((1 + indx))
[[ ${obj_count} -lt $indx ]] && break
$1 "$g" "$indx"
done
done
}

clone_and_upload() {
git_str="${GITHUB_USER}:${GITHUB_TOKEN}@github.com"
base_name=$(basename "$GITHUB_REPO")
git_dir=$TMP_DIR/${base_name}
git_repo=${GITHUB_REPO//github.com/${git_str}}
[[ -d "${git_dir}" ]] && rm -rf "${git_dir}"
git clone "$git_repo" "$git_dir"
cd "$git_dir" || return
git config user.name "rhdh-performance-bot"
git config user.email [email protected]
tmp_branch=$(mktemp -u XXXXXXXXXX)
git checkout -b "$tmp_branch"
mv -vf "$1" .
filename=$(basename "$1")
git add "$filename"
git commit -a -m "commit objects"
git push -f --set-upstream origin "$tmp_branch"
cd ..
sleep 5
upload_url="${GITHUB_REPO%.*}/blob/${tmp_branch}/${filename}"
curl -k "$(backstage_url)/api/catalog/locations" -X POST -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' --data-raw '{"type":"url","target":"'"${upload_url}"'"}'
}

# shellcheck disable=SC2016
create_api() {
export grp_indx=$1
export api_indx=$2
envsubst '${grp_indx} ${api_indx}' <"$WORKDIR/template/component/api.template" >>"$TMP_DIR/api.yaml"
}

# shellcheck disable=SC2016
create_cmp() {
export grp_indx=$1
export cmp_indx=$2
envsubst '${grp_indx} ${cmp_indx}' <"$WORKDIR/template/component/component.template" >>"$TMP_DIR/component.yaml"
}

create_group() {
token=$(get_token)
curl -s -k --location --request POST "$(keycloak_url)/auth/admin/realms/backstage/groups" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '"$token" \
--data-raw '{"name": "group'"${0}"'"}'
}

create_groups() {
echo "Creating Groups in Keycloak"
refresh_pid=$!
sleep 5
seq 1 "${GROUP_COUNT}" | xargs -n1 -P10 bash -c 'create_group'
kill $refresh_pid
}

create_user() {
token=$(get_token)
grp=$(echo "${0}%${GROUP_COUNT}" | bc)
[[ $grp -eq 0 ]] && grp=${GROUP_COUNT}
curl -s -k --location --request POST "$(keycloak_url)/auth/admin/realms/backstage/users" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer '"$token" \
--data-raw '{"firstName":"test'"${0}"'","lastName":"tester", "email":"test'"${0}"'@test.com", "enabled":"true", "username":"test'"${0}"'","groups":["/group'"${grp}"'"]}'
}

create_users() {
echo "Creating Users in Keycloak"
export GROUP_COUNT
refresh_pid=$!
sleep 5
seq 1 "${BACKSTAGE_USER_COUNT}" | xargs -n1 -P10 bash -c 'create_user'
kill $refresh_pid
}

token_lockfile="$TMP_DIR/token.lockfile"

get_token() {
token_file=$TMP_DIR/token.json
exec 3>"$token_lockfile"
flock 3 || {
echo "Failed to acquire lock"
exit 1
}
if [ ! -f "$token_file" ] || [ "$(date +%s)" -gt "$(jq -rc '.expires_in_timestamp' "$token_file")" ]; then
keycloak_pass=$(oc -n "${RHDH_NAMESPACE}" get secret credential-example-sso -o template --template='{{.data.ADMIN_PASSWORD}}' | base64 -d)
curl -s -k "$(keycloak_url)/auth/realms/master/protocol/openid-connect/token" -d username=admin -d "password=${keycloak_pass}" -d 'grant_type=password' -d 'client_id=admin-cli' | jq -r ".expires_in_timestamp = $(date -d '30 seconds' +%s)" >"$token_file"
fi
flock -u 3
jq -rc '.access_token' "$token_file"
}

export -f keycloak_url backstage_url backstage_url get_token create_group create_user
export kc_lockfile bs_lockfile token_lockfile
Loading

0 comments on commit 468ce13

Please sign in to comment.