From 3a8bcb06cb50c7fc37d8df4d25e28cdf12ff84c3 Mon Sep 17 00:00:00 2001 From: K Rin Date: Sun, 10 Nov 2024 10:25:49 +0800 Subject: [PATCH] Add FreeBSD pipeline. Signed-off-by: K Rin --- .github/workflows/freebsd-ci.yml | 36 +++++ Makefile | 22 ++- collector/fixtures/e2e-output-freebsd.txt | 185 ++++++++++++++++++++++ end-to-end-test-freebsd.sh | 131 +++++++++++++++ 4 files changed, 361 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/freebsd-ci.yml create mode 100644 collector/fixtures/e2e-output-freebsd.txt create mode 100755 end-to-end-test-freebsd.sh diff --git a/.github/workflows/freebsd-ci.yml b/.github/workflows/freebsd-ci.yml new file mode 100644 index 0000000000..565a0b1b84 --- /dev/null +++ b/.github/workflows/freebsd-ci.yml @@ -0,0 +1,36 @@ +name: freebsd-ci + +on: + push: + branches: + - master + pull_request: + branches: + - master + +permissions: + contents: read + +env: + GO_VERSION: "123" + +jobs: + test: + name: e2e-tests + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Setup FreeBSD + uses: vmactions/freebsd-vm@v1 + with: + envs: 'GO_VERSION' + usesh: true + prepare: | + pkg update -f + pkg install -y bash curl git gmake go${GO_VERSION} python + run: | + ln -s /usr/local/bin/bash /usr/bin/bash + gmake test-e2e + rm -rf "node_exporter/node_exporter/collector/fixtures/proc/self" diff --git a/Makefile b/Makefile index 0edd9a125a..25323917a4 100644 --- a/Makefile +++ b/Makefile @@ -28,12 +28,6 @@ MACH ?= $(shell uname -m) STATICCHECK_IGNORE = -ifeq ($(GOHOSTOS), linux) - test-e2e := test-e2e -else - test-e2e := skip-test-e2e -endif - # Use CGO for non-Linux builds. ifeq ($(GOOS), linux) PROMU_CONF ?= .promu.yml @@ -113,15 +107,17 @@ update_fixtures: rm -vf collector/fixtures/udev/.unpacked ./ttar -C collector/fixtures -c -f collector/fixtures/udev.ttar udev - .PHONY: test-e2e test-e2e: build collector/fixtures/sys/.unpacked collector/fixtures/udev/.unpacked - @echo ">> running end-to-end tests" - ./end-to-end-test.sh - -.PHONY: skip-test-e2e -skip-test-e2e: - @echo ">> SKIP running end-to-end tests on $(GOHOSTOS)" + if [ "$(GOHOSTOS)" = "linux" ]; then \ + ./end-to-end-test.sh; \ + elif [ "$(GOHOSTOS)" = "freebsd" ]; then \ + ./end-to-end-test-freebsd.sh; \ + fi + +# .PHONY: skip-test-e2e +# skip-test-e2e: +# @echo ">> SKIP running end-to-end tests on $(GOHOSTOS)" .PHONY: checkmetrics checkmetrics: $(PROMTOOL) diff --git a/collector/fixtures/e2e-output-freebsd.txt b/collector/fixtures/e2e-output-freebsd.txt new file mode 100644 index 0000000000..93b9e39cc0 --- /dev/null +++ b/collector/fixtures/e2e-output-freebsd.txt @@ -0,0 +1,185 @@ +# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles. +# TYPE go_gc_duration_seconds summary +# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent +# TYPE go_gc_gogc_percent gauge +# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes +# TYPE go_gc_gomemlimit_bytes gauge +# HELP go_goroutines Number of goroutines that currently exist. +# TYPE go_goroutines gauge +# HELP go_info Information about the Go environment. +# TYPE go_info gauge +# HELP go_memstats_alloc_bytes Number of bytes allocated in heap and currently in use. Equals to /memory/classes/heap/objects:bytes. +# TYPE go_memstats_alloc_bytes gauge +# HELP go_memstats_alloc_bytes_total Total number of bytes allocated in heap until now, even if released already. Equals to /gc/heap/allocs:bytes. +# TYPE go_memstats_alloc_bytes_total counter +# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. Equals to /memory/classes/profiling/buckets:bytes. +# TYPE go_memstats_buck_hash_sys_bytes gauge +# HELP go_memstats_frees_total Total number of heap objects frees. Equals to /gc/heap/frees:objects + /gc/heap/tiny/allocs:objects. +# TYPE go_memstats_frees_total counter +# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. Equals to /memory/classes/metadata/other:bytes. +# TYPE go_memstats_gc_sys_bytes gauge +# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and currently in use, same as go_memstats_alloc_bytes. Equals to /memory/classes/heap/objects:bytes. +# TYPE go_memstats_heap_alloc_bytes gauge +# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used. Equals to /memory/classes/heap/released:bytes + /memory/classes/heap/free:bytes. +# TYPE go_memstats_heap_idle_bytes gauge +# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use. Equals to /memory/classes/heap/objects:bytes + /memory/classes/heap/unused:bytes +# TYPE go_memstats_heap_inuse_bytes gauge +# HELP go_memstats_heap_objects Number of currently allocated objects. Equals to /gc/heap/objects:objects. +# TYPE go_memstats_heap_objects gauge +# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS. Equals to /memory/classes/heap/released:bytes. +# TYPE go_memstats_heap_released_bytes gauge +# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system. Equals to /memory/classes/heap/objects:bytes + /memory/classes/heap/unused:bytes + /memory/classes/heap/released:bytes + /memory/classes/heap/free:bytes. +# TYPE go_memstats_heap_sys_bytes gauge +# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection. +# TYPE go_memstats_last_gc_time_seconds gauge +# HELP go_memstats_mallocs_total Total number of heap objects allocated, both live and gc-ed. Semantically a counter version for go_memstats_heap_objects gauge. Equals to /gc/heap/allocs:objects + /gc/heap/tiny/allocs:objects. +# TYPE go_memstats_mallocs_total counter +# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures. Equals to /memory/classes/metadata/mcache/inuse:bytes. +# TYPE go_memstats_mcache_inuse_bytes gauge +# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system. Equals to /memory/classes/metadata/mcache/inuse:bytes + /memory/classes/metadata/mcache/free:bytes. +# TYPE go_memstats_mcache_sys_bytes gauge +# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures. Equals to /memory/classes/metadata/mspan/inuse:bytes. +# TYPE go_memstats_mspan_inuse_bytes gauge +# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system. Equals to /memory/classes/metadata/mspan/inuse:bytes + /memory/classes/metadata/mspan/free:bytes. +# TYPE go_memstats_mspan_sys_bytes gauge +# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place. Equals to /gc/heap/goal:bytes. +# TYPE go_memstats_next_gc_bytes gauge +# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations. Equals to /memory/classes/other:bytes. +# TYPE go_memstats_other_sys_bytes gauge +# HELP go_memstats_stack_inuse_bytes Number of bytes obtained from system for stack allocator in non-CGO environments. Equals to /memory/classes/heap/stacks:bytes. +# TYPE go_memstats_stack_inuse_bytes gauge +# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator. Equals to /memory/classes/heap/stacks:bytes + /memory/classes/os-stacks:bytes. +# TYPE go_memstats_stack_sys_bytes gauge +# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. +# TYPE go_memstats_sys_bytes gauge +# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads +# TYPE go_sched_gomaxprocs_threads gauge +# HELP go_threads Number of OS threads created. +# TYPE go_threads gauge +# HELP node_boot_time_seconds Unix time of last boot, including microseconds. +# TYPE node_boot_time_seconds gauge +# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode. +# TYPE node_cpu_seconds_total counter +# HELP node_exec_context_switches_total Context switches since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_context_switches_total counter +# HELP node_exec_device_interrupts_total Device interrupts since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_device_interrupts_total counter +# HELP node_exec_forks_total Number of fork() calls since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_forks_total counter +# HELP node_exec_software_interrupts_total Software interrupts since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_software_interrupts_total counter +# HELP node_exec_system_calls_total System calls since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_system_calls_total counter +# HELP node_exec_traps_total Traps since system boot. Resets at architecture unsigned integer. +# TYPE node_exec_traps_total counter +# HELP node_exporter_build_info A metric with a constant '1' value labeled by version, revision, branch, goversion from which node_exporter was built, and the goos and goarch for the build. +# TYPE node_exporter_build_info gauge +# HELP node_load1 1m load average. +# TYPE node_load1 gauge +# HELP node_load15 15m load average. +# TYPE node_load15 gauge +# HELP node_load5 5m load average. +# TYPE node_load5 gauge +# HELP node_memory_active_bytes Recently used by userland +# TYPE node_memory_active_bytes gauge +# HELP node_memory_buffer_bytes Disk IO Cache entries for non ZFS filesystems, only usable by kernel +# TYPE node_memory_buffer_bytes gauge +# HELP node_memory_cache_bytes Almost free, backed by swap or files, available for re-allocation +# TYPE node_memory_cache_bytes gauge +# HELP node_memory_free_bytes Unallocated, available for allocation +# TYPE node_memory_free_bytes gauge +# HELP node_memory_inactive_bytes Not recently used by userland +# TYPE node_memory_inactive_bytes gauge +# HELP node_memory_laundry_bytes Dirty not recently used by userland +# TYPE node_memory_laundry_bytes gauge +# HELP node_memory_size_bytes Total physical memory size +# TYPE node_memory_size_bytes gauge +# HELP node_memory_swap_in_bytes_total Bytes paged in from swap devices +# TYPE node_memory_swap_in_bytes_total counter +# HELP node_memory_swap_out_bytes_total Bytes paged out to swap devices +# TYPE node_memory_swap_out_bytes_total counter +# HELP node_memory_swap_size_bytes Total swap memory size +# TYPE node_memory_swap_size_bytes gauge +# HELP node_memory_swap_used_bytes Currently allocated swap +# TYPE node_memory_swap_used_bytes gauge +# HELP node_memory_user_wired_bytes Locked in memory by user, mlock, etc +# TYPE node_memory_user_wired_bytes gauge +# HELP node_memory_wired_bytes Locked in memory by kernel, mlock, etc +# TYPE node_memory_wired_bytes gauge +# HELP node_netisr_bindthreads netisr threads bound to CPUs +# TYPE node_netisr_bindthreads gauge +node_netisr_bindthreads 0 +# HELP node_netisr_defaultqlimit netisr default queue limit +# TYPE node_netisr_defaultqlimit gauge +node_netisr_defaultqlimit 256 +# HELP node_netisr_maxprot netisr maximum protocols +# TYPE node_netisr_maxprot gauge +node_netisr_maxprot 16 +# HELP node_netisr_maxqlimit netisr maximum queue limit +# TYPE node_netisr_maxqlimit gauge +node_netisr_maxqlimit 10240 +# HELP node_netisr_maxthreads netisr maximum thread count +# TYPE node_netisr_maxthreads gauge +node_netisr_maxthreads 1 +# HELP node_netisr_numthreads netisr current thread count +# TYPE node_netisr_numthreads gauge +node_netisr_numthreads 1 +# HELP node_network_receive_bytes_total Network device statistic receive_bytes. +# TYPE node_network_receive_bytes_total counter +# HELP node_network_receive_drop_total Network device statistic receive_drop. +# TYPE node_network_receive_drop_total counter +# HELP node_network_receive_errs_total Network device statistic receive_errs. +# TYPE node_network_receive_errs_total counter +# HELP node_network_receive_multicast_total Network device statistic receive_multicast. +# TYPE node_network_receive_multicast_total counter +# HELP node_network_receive_packets_total Network device statistic receive_packets. +# TYPE node_network_receive_packets_total counter +# HELP node_network_transmit_bytes_total Network device statistic transmit_bytes. +# TYPE node_network_transmit_bytes_total counter +# HELP node_network_transmit_drop_total Network device statistic transmit_drop. +# TYPE node_network_transmit_drop_total counter +# HELP node_network_transmit_errs_total Network device statistic transmit_errs. +# TYPE node_network_transmit_errs_total counter +# HELP node_network_transmit_multicast_total Network device statistic transmit_multicast. +# TYPE node_network_transmit_multicast_total counter +# HELP node_network_transmit_packets_total Network device statistic transmit_packets. +# TYPE node_network_transmit_packets_total counter +# HELP node_os_info A metric with a constant '1' value labeled by build_id, id, id_like, image_id, image_version, name, pretty_name, variant, variant_id, version, version_codename, version_id. +# TYPE node_os_info gauge +node_os_info{build_id="",id="ubuntu",id_like="debian",image_id="",image_version="",name="Ubuntu",pretty_name="Ubuntu 20.04.2 LTS",variant="",variant_id="",version="20.04.2 LTS (Focal Fossa)",version_codename="focal",version_id="20.04"} 1 +# HELP node_os_version Metric containing the major.minor part of the OS version. +# TYPE node_os_version gauge +node_os_version{id="ubuntu",id_like="debian",name="Ubuntu"} 20.04 +# HELP node_scrape_collector_duration_seconds node_exporter: Duration of a collector scrape. +# TYPE node_scrape_collector_duration_seconds gauge +# HELP node_scrape_collector_success node_exporter: Whether a collector succeeded. +# TYPE node_scrape_collector_success gauge +node_scrape_collector_success{collector="boottime"} 1 +node_scrape_collector_success{collector="cpu"} 1 +node_scrape_collector_success{collector="exec"} 1 +node_scrape_collector_success{collector="loadavg"} 1 +node_scrape_collector_success{collector="meminfo"} 1 +node_scrape_collector_success{collector="netdev"} 1 +node_scrape_collector_success{collector="netisr"} 1 +node_scrape_collector_success{collector="os"} 1 +node_scrape_collector_success{collector="textfile"} 1 +node_scrape_collector_success{collector="time"} 1 +# HELP node_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise +# TYPE node_textfile_scrape_error gauge +node_textfile_scrape_error 0 +# HELP node_time_seconds System time in seconds since epoch (1970). +# TYPE node_time_seconds gauge +# HELP node_time_zone_offset_seconds System time zone offset in seconds. +# TYPE node_time_zone_offset_seconds gauge +# HELP promhttp_metric_handler_errors_total Total number of internal errors encountered by the promhttp metric handler. +# TYPE promhttp_metric_handler_errors_total counter +promhttp_metric_handler_errors_total{cause="encoding"} 0 +promhttp_metric_handler_errors_total{cause="gathering"} 0 +# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served. +# TYPE promhttp_metric_handler_requests_in_flight gauge +promhttp_metric_handler_requests_in_flight 1 +# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code. +# TYPE promhttp_metric_handler_requests_total counter +promhttp_metric_handler_requests_total{code="200"} 0 +promhttp_metric_handler_requests_total{code="500"} 0 +promhttp_metric_handler_requests_total{code="503"} 0 diff --git a/end-to-end-test-freebsd.sh b/end-to-end-test-freebsd.sh new file mode 100755 index 0000000000..f646499e16 --- /dev/null +++ b/end-to-end-test-freebsd.sh @@ -0,0 +1,131 @@ +#!/usr/local/bin/bash + +set -euf -o pipefail + +enabled_collectors=$(cat << COLLECTORS + cpu + meminfo + netdev + textfile +COLLECTORS +) +disabled_collectors=$(cat << COLLECTORS + filesystem + uname + zfs +COLLECTORS +) +cd "$(dirname $0)" + +port="$((10000 + (RANDOM % 10000)))" +tmpdir=$(mktemp -d /tmp/node_exporter_e2e_test.XXXXXX) + +skip_re="^(go_|node_exporter_build_info|node_boot_time_seconds|node_cpu_seconds_total|node_scrape_collector_duration_seconds|node_network_|node_memory_|node_exec_|node_time_|node_load)" + +arch="$(uname -m)" + +fixture='collector/fixtures/e2e-output-freebsd.txt'; + +# Only test CPU info collection on x86_64. +case "${arch}" in + x86_64) + cpu_info_collector='--collector.cpu.info' + cpu_info_bugs='^(cpu_meltdown|spectre_.*|mds)$' + cpu_info_flags='^(aes|avx.?|constant_tsc)$' + ;; + *) + cpu_info_collector='--no-collector.cpu.info' + cpu_info_bugs='' + cpu_info_flags='' + ;; +esac + +keep=0; update=0; verbose=0 +while getopts 'hkuv' opt +do + case "$opt" in + k) + keep=1 + ;; + u) + update=1 + ;; + v) + verbose=1 + set -x + ;; + *) + echo "Usage: $0 [-k] [-u] [-v]" + echo " -k: keep temporary files and leave node_exporter running" + echo " -u: update fixture" + echo " -v: verbose output" + exit 1 + ;; + esac +done + +if [ ! -x ./node_exporter ] +then + echo './node_exporter not found. Consider running `go build` first.' >&2 + exit 1 +fi + +./node_exporter \ + --path.rootfs="collector/fixtures" \ + --path.procfs="collector/fixtures/proc" \ + --path.sysfs="collector/fixtures/sys" \ + --path.udev.data="collector/fixtures/udev/data" \ + $(for c in ${enabled_collectors}; do echo --collector.${c} ; done) \ + $(for c in ${disabled_collectors}; do echo --no-collector.${c} ; done) \ + --web.listen-address "127.0.0.1:${port}" \ + --log.level="debug" > "${tmpdir}/node_exporter.log" 2>&1 & + +echo $! > "${tmpdir}/node_exporter.pid" + +finish() { + if [ $? -ne 0 -o ${verbose} -ne 0 ] + then + cat << EOF >&2 +LOG ===================== +$(cat "${tmpdir}/node_exporter.log") +========================= +EOF + fi + + if [ ${update} -ne 0 ] + then + cp "${tmpdir}/e2e-output.txt" "${fixture}" + fi + + if [ ${keep} -eq 0 ] + then + kill -9 "$(cat ${tmpdir}/node_exporter.pid)" + # This silences the "Killed" message + set +e + wait "$(cat ${tmpdir}/node_exporter.pid)" > /dev/null 2>&1 + rm -rf "${tmpdir}" + fi +} + +trap finish EXIT + +get() { + if command -v curl > /dev/null 2>&1 + then + curl -s -f "$@" + elif command -v wget > /dev/null 2>&1 + then + wget -O - "$@" + else + echo "Neither curl nor wget found" + exit 1 + fi +} + +sleep 1 + +get "127.0.0.1:${port}/metrics" | grep -E -v "${skip_re}" > "${tmpdir}/e2e-output.txt" + +diff -u \ + "${fixture}" \ + "${tmpdir}/e2e-output.txt"