Skip to content

Add hotreload.sh #2110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
8 changes: 7 additions & 1 deletion collector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
if(ADDRESS_SANITIZER)
set(DISABLE_PROFILING ON)
set(USE_VALGRIND OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined -DGRPC_ASAN_SUPRESSED")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined -DGRPC_ASAN_SUPPRESSED")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to add this change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I did, it has been wrong since we first added it.

endif()

if(THREAD_SANITIZER)
set(DISABLE_PROFILING ON)
set(USE_VALGRIND OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -DGRPC_TSAN_SUPPRESSED")
endif()

if(USE_VALGRIND)
Expand Down
1 change: 1 addition & 0 deletions collector/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ cmake-configure/collector:
-DDISABLE_PROFILING=$(DISABLE_PROFILING) \
-DUSE_VALGRIND=$(USE_VALGRIND) \
-DADDRESS_SANITIZER=$(ADDRESS_SANITIZER) \
-DTHREAD_SANITIZER=$(THREAD_SANITIZER) \
-DTRACE_SINSP_EVENTS=$(TRACE_SINSP_EVENTS) \
-DBPF_DEBUG_MODE=$(BPF_DEBUG_MODE) \
-DCOLLECTOR_VERSION=$(COLLECTOR_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion collector/container/devel/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
set -eo pipefail

dnf upgrade -y
dnf install -y libasan elfutils-libelf
dnf install -y libasan libubsan libtsan elfutils-libelf
18 changes: 18 additions & 0 deletions docs/how-to-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ Or similarly via a CLI parameter:
$ collector --grpc-server=
```

## Hotreload on local k8s cluster

If using some sort of local k8s cluster for development (KinD, k3s, minikube)
that has access to your local filesystem, you can use the
[hotreload.sh](../utilities/hotreload.sh) script to run the collector binary in
the cluster without rebuilding the entire image.

Start by deploying stackrox to your cluster using the `deploy-local.sh` script
from the main repo, the run `hotreload.sh` to have the collector repository
mounted into the collector container and its command changed to run the binary
in `cmake-build/collector/collector`. Once that is done, you can recompile the
binary by using the `make -C collector container/bin/collector` command or by
exec'ing into the builder container directly and compiling from there with
cmake.

This is also an easy way to run collector under thread or address sanitizer, but
you will need to deploy an image built with the `image-dev` make target.

### Development with an IDE (CLion)

#### Setup
Expand Down
194 changes: 194 additions & 0 deletions utilities/hotreload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#!/usr/bin/env bash

set -euo pipefail

NAMESPACE="${NAMESPACE:-stackrox}"
REVERT=0

# The following line allows to symlink the script somewhere in PATH for
# easier use, has no effect if run directly.
REAL_SCRIPT="$(realpath "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(cd -- "$( dirname -- "${REAL_SCRIPT}")" &> /dev/null && pwd)"
COLLECTOR_PATH="$(realpath "${SCRIPT_DIR:-}/..")"

function usage() {
cat << EOF
$(basename "$0") [OPTIONS]

Configure a running collector pod to use a local binary.

OPTIONS:
-h, --help
Show this help.
-r, --revert
Remove any configuration added by this script.
-p, --path
Override the path to the collector repo.
-n, --namespace
Set the namespace the collector daemonset is deployed to.
Default: stackrox
EOF
}

function die() {
echo >&2 "$1"
exit 1
}

function check_command() {
if ! command -v "$1" &> /dev/null; then
die "$1 not found. Make sure it is in your path"
fi
}

function krox() {
kubectl -n "${NAMESPACE}" "$@"
}

function patch_hotreload() {
cat << EOF | jq -Mc \
--arg hostPath "$COLLECTOR_PATH" \
'.spec.template.spec.volumes.[0].hostPath.path |= $hostPath'
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "collector",
"command": ["/host/src/cmake-build/collector/collector"],
"volumeMounts": [
{
"mountPath": "/host/src",
"name": "collector-src",
"readOnly": true
}
]
}
],
"volumes": [
{
"hostPath": {
"path": "\$hostPath",
"type": ""
},
"name": "collector-src"
}
]
}
}
}
}
EOF
}

function revert_command() {
cat << EOF | jq -Mc
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "collector",
"command": ["collector"]
}
]
}
}
}
}
EOF
}

function remove_mount() {
jq -Mcn \
--arg container "$1" \
--arg volume "$2" \
'[{"op":"remove","path":"/spec/template/spec/containers/\($container)/volumeMounts/\($volume)"}]'
}

function remove_volume() {
jq -Mcn \
--arg volume "$1" \
'[{"op":"remove","path":"/spec/template/spec/volumes/\($volume)"}]'
}

function find_index() {
local element="$1"
local filter="$2"
ret="$(krox get -o json ds/collector | jq "$element | map($filter) | index(true)")"
if [[ "$ret" == "null" ]]; then
die "Filter failed for '$filter'"
fi
echo "$ret"
}

function add_hotreload() {
krox patch ds collector -p "$(patch_hotreload)"
}

function revert_config() {
local collector_idx
collector_idx="$(find_index ".spec.template.spec.containers" '.name == "collector"')"
local mount_idx
mount_idx="$(find_index ".spec.template.spec.containers.[$collector_idx].volumeMounts" '.name == "collector-src"')"
local volume_idx
volume_idx="$(find_index ".spec.template.spec.volumes" '.name == "collector-src"')"

krox patch ds collector -p "$(revert_command)"
krox patch ds collector --type=json -p "$(remove_mount "$collector_idx" "$mount_idx")"
krox patch ds collector --type=json -p "$(remove_volume "$volume_idx")"
}

check_command jq
check_command kubectl

if ! krox get ds/collector &> /dev/null; then
die "collector daemonset not found (did you forget to deploy stackrox?)"
fi

TEMP=$(getopt -o 'hrp:n:' -l 'help,revert,path:,namespace:' -n "$0" -- "$@")

# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
exit 1
fi

eval set -- "$TEMP"
unset TEMP

while true; do
case "${1:-}" in
'-h' | '--help')
usage
exit 0
;;

'-r' | '--revert')
REVERT=1
shift
;;

'-p' | '--path')
COLLECTOR_PATH="$2"
shift 2
;;

'-n' | '--namespace')
NAMESPACE="$2"
shift 2
;;

'--')
shift
break
;;
esac
done

if ((REVERT)); then
revert_config
else
add_hotreload
fi
Loading