Skip to content
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

NETOBSERV-1908 Be able to customize namespace #103

Open
wants to merge 4 commits into
base: main
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
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ COPY .mk/ .mk/
# Build collector
RUN GOARCH=$TARGETARCH make compile

# Install oc to allow collector to run commands
RUN set -x; \
OC_TAR_URL="https://mirror.openshift.com/pub/openshift-v4/$(uname -m)/clients/ocp/latest/openshift-client-linux.tar.gz" && \
curl -L -q -o /tmp/oc.tar.gz "$OC_TAR_URL" && \
tar -C /tmp -xvf /tmp/oc.tar.gz oc kubectl

# Embedd commands in case users want to pull it from collector image
RUN USER=netobserv VERSION=main make oc-commands

Expand All @@ -35,7 +41,11 @@ RUN mkdir -p output
# Create final image from ubi + built binary and command
FROM --platform=$TARGETPLATFORM registry.access.redhat.com/ubi9/ubi:9.4
WORKDIR /

COPY --from=builder /opt/app-root/build .
COPY --from=builder /opt/app-root/build .
COPY --from=builder /tmp/oc /usr/bin/oc
COPY --from=builder /tmp/kubectl /usr/bin/kubectl
COPY --from=builder --chown=65532:65532 /opt/app-root/output /output
USER 65532:65532

Expand Down
31 changes: 20 additions & 11 deletions cmd/flow_capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,20 @@ func runFlowCaptureOnAddr(port int, filename string) {
// terminate capture if max bytes reached
totalBytes = totalBytes + int64(bytes)
if totalBytes > maxBytes {
log.Infof("Capture reached %s, exiting now...", sizestr.ToString(maxBytes))
return
if exit := onLimitReached(); exit {
log.Infof("Capture reached %s, exiting now...", sizestr.ToString(maxBytes))
return
}
}

// terminate capture if max time reached
now := currentTime()
duration := now.Sub(startupTime)
if int(duration) > int(maxTime) {
log.Infof("Capture reached %s, exiting now...", maxTime)
return
if exit := onLimitReached(); exit {
log.Infof("Capture reached %s, exiting now...", sizestr.ToString(maxBytes))
return
}
}

captureStarted = true
Expand Down Expand Up @@ -241,7 +245,7 @@ func toSize(fieldName string) int {
func updateTable() {
// don't refresh terminal too often to avoid blinking
now := currentTime()
if int(now.Sub(lastRefresh)) > int(maxRefreshRate) {
if !captureEnded && int(now.Sub(lastRefresh)) > int(maxRefreshRate) {
lastRefresh = now
resetTerminal()

Expand All @@ -251,12 +255,18 @@ func updateTable() {
fmt.Printf("Log level: %s ", logLevel)
fmt.Printf("Duration: %s ", duration.Round(time.Second))
fmt.Printf("Capture size: %s\n", sizestr.ToString(totalBytes))
if len(strings.TrimSpace(filter)) > 0 {
fmt.Printf("Filters: %s\n", filter)
if len(strings.TrimSpace(options)) > 0 {
fmt.Printf("Options: %s\n", options)
}
if strings.Contains(options, "background=true") {
fmt.Printf("Showing last: %d\n", flowsToShow)
fmt.Printf("Display: %s\n", strings.Join(display, ","))
fmt.Printf("Enrichment: %s\n", strings.Join(enrichement, ","))
} else {
fmt.Printf("Showing last: %d Use Up / Down keyboard arrows to increase / decrease limit\n", flowsToShow)
fmt.Printf("Display: %s Use Left / Right keyboard arrows to cycle views\n", strings.Join(display, ","))
fmt.Printf("Enrichment: %s Use Page Up / Page Down keyboard keys to cycle enrichment scopes\n", strings.Join(enrichement, ","))
}
fmt.Printf("Showing last: %d Use Up / Down keyboard arrows to increase / decrease limit\n", flowsToShow)
fmt.Printf("Display: %s Use Left / Right keyboard arrows to cycle views\n", strings.Join(display, ","))
fmt.Printf("Enrichment: %s Use Page Up / Page Down keyboard keys to cycle enrichment scopes\n", strings.Join(enrichement, ","))
}

if slices.Contains(display, rawDisplay) {
Expand Down Expand Up @@ -393,7 +403,6 @@ func updateTable() {
fmt.Printf("Type anything to filter incoming flows in view\n")
}
}

}
}

Expand Down
12 changes: 8 additions & 4 deletions cmd/packet_capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,21 @@ func runPacketCaptureOnAddr(port int, filename string) {
// terminate capture if max bytes reached
totalBytes = totalBytes + int64(len(fp.GenericMap.Value))
if totalBytes > maxBytes {
log.Infof("Capture reached %s, exiting now...", sizestr.ToString(maxBytes))
return
if exit := onLimitReached(); exit {
log.Infof("Capture reached %s, exiting now...", sizestr.ToString(maxBytes))
return
}
}
totalPackets = totalPackets + 1

// terminate capture if max time reached
now := currentTime()
duration := now.Sub(startupTime)
if int(duration) > int(maxTime) {
log.Infof("Capture reached %s, exiting now...", maxTime)
return
if exit := onLimitReached(); exit {
log.Infof("Capture reached %s, exiting now...", maxTime)
return
}
}

captureStarted = true
Expand Down
50 changes: 47 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var (
logLevel string
ports []int
nodes []string
filter string
options string
maxTime time.Duration
maxBytes int64

Expand Down Expand Up @@ -56,6 +56,7 @@ var (
captureType = "Flow"
outputBuffer *bytes.Buffer
captureStarted = false
captureEnded = false
stopReceived = false
keyboardError = ""
)
Expand All @@ -71,7 +72,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&logLevel, "loglevel", "l", "info", "Log level")
rootCmd.PersistentFlags().IntSliceVarP(&ports, "ports", "", []int{9999}, "TCP ports to listen")
rootCmd.PersistentFlags().StringSliceVarP(&nodes, "nodes", "", []string{""}, "Node names per port (optionnal)")
rootCmd.PersistentFlags().StringVarP(&filter, "filter", "", "", "Filter(s)")
rootCmd.PersistentFlags().StringVarP(&options, "options", "", "", "Options(s)")
rootCmd.PersistentFlags().DurationVarP(&maxTime, "maxtime", "", 5*time.Minute, "Maximum capture time")
rootCmd.PersistentFlags().Int64VarP(&maxBytes, "maxbytes", "", 50000000, "Maximum capture bytes")

Expand Down Expand Up @@ -100,10 +101,22 @@ func initConfig() {
log.Fatalf("specified nodes names doesn't match ports length")
}

log.Infof("Running network-observability-cli\nLog level: %s\nFilter(s): %s", logLevel, filter)
printBanner()
log.Infof("Log level: %s\nOption(s): %s", logLevel, options)
showKernelVersion()
}

func printBanner() {
fmt.Print(`
------------------------------------------------------------------------
_ _ _ _ ___ _ ___
| \| |___| |_ ___| |__ ___ ___ _ ___ __ / __| | |_ _|
| .' / -_) _/ _ \ '_ (_-</ -_) '_\ V / | (__| |__ | |
|_|\_\___|\__\___/_.__/__/\___|_| \_/ \___|____|___|

------------------------------------------------------------------------`)
}

func showKernelVersion() {
output, err := exec.Command("uname", "-r").Output()
if err != nil {
Expand All @@ -115,3 +128,34 @@ func showKernelVersion() {
log.Infof("Kernel version: %s", strings.TrimSpace(string(output)))
}
}

func onLimitReached() bool {
shouldExit := false
if !captureEnded {
if strings.Contains(options, "background=true") {
captureEnded = true
resetTerminal()
out, err := exec.Command("/oc-netobserv", "stop").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", out)
fmt.Print(`Thank you for using...`)
printBanner()
fmt.Print(`

- Download the generated output using 'oc netobserv copy' command

- Once finished, clean the collector pod using 'oc netobserv cleanup'

See you soon !


`)
} else {
shouldExit = true
}
}

return shouldExit
}
2 changes: 1 addition & 1 deletion cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestDefaultArguments(t *testing.T) {
assert.Equal(t, "info", logLevel)
assert.Equal(t, []int{9999}, ports)
assert.Equal(t, []string{""}, nodes)
assert.Empty(t, filter)
assert.Empty(t, options)
}

func setup() {
Expand Down
63 changes: 50 additions & 13 deletions commands/netobserv
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,19 @@ if [ -z "${isE2E+x}" ]; then isE2E=false; fi
if [ -z "${captureStarted+x}" ]; then captureStarted=false; fi
# prompt copy by default
if [ -z "${copy+x}" ]; then copy="prompt"; fi
# run foreground by default
if [ -z "${runBackground+x}" ]; then runBackground="false"; fi

# interface filter such as 'br-ex' or pcap filter such as 'tcp,80'
filter=""
# options such as filters, background etc
options=""

# namespace for this run
namespace="netobserv-cli"

if [ -n "$NETOBSERV_NAMESPACE" ]; then
echo "using custom namespace $NETOBSERV_NAMESPACE"
namespace="$NETOBSERV_NAMESPACE"
fi

# CLI image to use
img="quay.io/netobserv/network-observability-cli:main"
Expand Down Expand Up @@ -43,7 +53,7 @@ function flows() {
exit 0 ;;
*)
shift # remove first argument
filter="$*"
options="$*"
# run flows command
command="flows" ;;
esac
Expand All @@ -56,7 +66,7 @@ function packets() {
exit 0 ;;
*)
shift # remove first argument
filter="$*"
options="$*"
# run packets command
command="packets" ;;
esac
Expand All @@ -72,12 +82,15 @@ case "$1" in
echo "Syntax: netobserv [flows|packets|cleanup] [options]"
echo
echo "commands:"
echo " flows Capture flows information. You can specify an optional interface name as filter such as 'netobserv flows br-ex'."
echo " flows Capture flows information in JSON format."
echo " Options:"
flows_usage
echo " packets Capture packets information in pcap format."
echo " Options:"
packets_usage
echo " follow Follow collector logs when running in background."
echo " stop Stop collection by removing agent daemonset."
echo " copy Copy generated files locally."
echo " cleanup Remove netobserv components."
echo " version Print software version."
echo
Expand All @@ -90,6 +103,18 @@ case "$1" in
flows $* ;;
"packets")
packets $* ;;
"follow")
# run follow command
follow
exit 0 ;;
"stop")
# run deleteDaemonset command
deleteDaemonset
exit 0 ;;
"copy")
# run copy output command
copyOutput
exit 0 ;;
"cleanup")
# run cleanup command
cleanup
Expand All @@ -101,24 +126,36 @@ esac

trap cleanup EXIT

setup $command $filter
setup $command $options

runCommand="sleep infinity"
execCommand="/network-observability-cli get-$command ${options:+"--options" "${options//--/}"} --loglevel $logLevel --maxtime $maxTime --maxbytes $maxBytes"
if [[ "$runBackground" == "true" ]]; then
runCommand="$execCommand & $runCommand"
execCommand=""
fi

echo "Running network-observability-cli get-$command... "
${K8S_CLI_BIN} run \
-n netobserv-cli \
-n $namespace \
collector \
--image=$img\
--image-pull-policy='Always' \
--overrides='{ "spec": { "serviceAccount": "netobserv-cli" } }' \
--restart='Never' \
--command -- sleep infinity
--command -- $runCommand

${K8S_CLI_BIN} wait \
-n netobserv-cli \
-n $namespace \
--for=condition=Ready pod/collector || exit 1

captureStarted=true

${K8S_CLI_BIN} exec -i --tty \
-n netobserv-cli \
collector \
-- /network-observability-cli get-$command ${filter:+"--filter" "${filter//--/}"} --loglevel $logLevel --maxtime $maxTime --maxbytes $maxBytes
if [ -n "${execCommand}" ]; then
${K8S_CLI_BIN} exec -i --tty \
-n $namespace \
collector \
-- $execCommand
else
echo "Background capture started. Use 'oc netobserv follow' to see it's progress."
fi
2 changes: 1 addition & 1 deletion e2e/script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestHelpCommand(t *testing.T) {
assert.Contains(t, str, "Find more information at: https://github.com/netobserv/network-observability-cli/")
// ensure help to display proper options
assert.Contains(t, str, "Syntax: netobserv [flows|packets|cleanup] [options]")
assert.Contains(t, str, "flows Capture flows information. You can specify an optional interface name as filter such as 'netobserv flows br-ex'.")
assert.Contains(t, str, "flows Capture flows information in JSON format.")
assert.Contains(t, str, "packets Capture packets information in pcap format.")
assert.Contains(t, str, "cleanup Remove netobserv components.")
assert.Contains(t, str, "version Print software version.")
Expand Down
2 changes: 1 addition & 1 deletion res/collector-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: collector
namespace: netobserv-cli
namespace: "{{NAMESPACE}}"
spec:
selector:
run: collector
Expand Down
4 changes: 2 additions & 2 deletions res/flow-capture.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: netobserv-cli
namespace: netobserv-cli
namespace: "{{NAMESPACE}}"
labels:
app: netobserv-cli
spec:
Expand Down Expand Up @@ -131,7 +131,7 @@ spec:
"write":{
"type":"grpc",
"grpc":{
"targetHost":"collector.netobserv-cli.svc.cluster.local",
"targetHost":"{{TARGET_HOST}}",
"targetPort":9999
}
}
Expand Down
2 changes: 1 addition & 1 deletion res/namespace.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
kind: Namespace
apiVersion: v1
metadata:
name: netobserv-cli
name: "{{NAME}}"
labels:
app: netobserv
pod-security.kubernetes.io/enforce: privileged
Expand Down
4 changes: 2 additions & 2 deletions res/packet-capture.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: netobserv-cli
namespace: netobserv-cli
namespace: "{{NAMESPACE}}"
labels:
app: netobserv-cli
spec:
Expand Down Expand Up @@ -115,7 +115,7 @@ spec:
"write":{
"type":"grpc",
"grpc":{
"targetHost":"collector.netobserv-cli.svc.cluster.local",
"targetHost":"{{TARGET_HOST}}",
"targetPort":9999
}
}
Expand Down
Loading
Loading