From 642d679b873d04c4752234dd543ee40605939a9b Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Wed, 1 Nov 2023 17:39:24 +0000 Subject: [PATCH 1/6] [zuul] Add zuul jobs to sg-core Depends-On: http://github.com/infrawatch/service-telemetry-operator/pull/512 --- .zuul.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .zuul.yaml diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 00000000..b3f8da23 --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,8 @@ + +--- +- project: + name: infrawatch/sg-core + github-check: + jobs: + - stf-crc-latest-nightly_bundles + - stf-crc-latest-local_build From e4e9d7b5bfe6ca7efa3d7babb135bee0e4d300af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20Wysoglad?= Date: Tue, 14 Nov 2023 07:26:12 +0100 Subject: [PATCH 2/6] Add prometheus to devstack plugin (#123) * Add prometheus to devstack plugin * Add uidmap installation for ubuntu distributions In order to interact with podman, we need the newuidmap binary. I've seen this being present on centos vms by default, but on some ubuntu / debian vms this isn't the case and the plugin fails to pull images. --- .../observabilityclient-files/prometheus.yaml | 2 + devstack/plugin.sh | 136 ++++++++++++++---- devstack/prometheus-files/prometheus.yml | 4 + .../scrape_configs/prometheus | 4 + .../prometheus-files/scrape_configs/sg-core | 4 + devstack/settings | 24 ++++ .../{ => sg-core-files}/sg-core.conf.yaml | 0 7 files changed, 143 insertions(+), 31 deletions(-) create mode 100644 devstack/observabilityclient-files/prometheus.yaml create mode 100644 devstack/prometheus-files/prometheus.yml create mode 100644 devstack/prometheus-files/scrape_configs/prometheus create mode 100644 devstack/prometheus-files/scrape_configs/sg-core rename devstack/{ => sg-core-files}/sg-core.conf.yaml (100%) diff --git a/devstack/observabilityclient-files/prometheus.yaml b/devstack/observabilityclient-files/prometheus.yaml new file mode 100644 index 00000000..9ff13455 --- /dev/null +++ b/devstack/observabilityclient-files/prometheus.yaml @@ -0,0 +1,2 @@ +host: localhost +port: 9090 diff --git a/devstack/plugin.sh b/devstack/plugin.sh index f2734547..afef031c 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -1,51 +1,125 @@ -function preinstall_sg-core { +function install_container_executable { install_package $SG_CORE_CONTAINER_EXECUTABLE + if is_ubuntu; then + install_package uidmap + fi } +### sg-core ### function install_sg-core { $SG_CORE_CONTAINER_EXECUTABLE pull $SG_CORE_CONTAINER_IMAGE } function configure_sg-core { sudo mkdir -p `dirname $SG_CORE_CONF` - sudo cp $SG_CORE_DIR/devstack/sg-core.conf.yaml $SG_CORE_CONF + sudo cp $SG_CORE_DIR/devstack/sg-core-files/sg-core.conf.yaml $SG_CORE_CONF } function init_sg-core { $SG_CORE_CONTAINER_EXECUTABLE run -v $SG_CORE_CONF:/etc/sg-core.conf.yaml --network host --name sg-core -d $SG_CORE_CONTAINER_IMAGE } +### prometheus ### +function install_prometheus { + $SG_CORE_CONTAINER_EXECUTABLE pull $PROMETHEUS_CONTAINER_IMAGE +} + +function configure_prometheus { + BASE_CONFIG_FILE=$SG_CORE_DIR/devstack/prometheus-files/prometheus.yml + RESULT_CONFIG_FILE=$SG_CORE_WORKDIR/prometheus.yml + + cat $BASE_CONFIG_FILE > $RESULT_CONFIG_FILE + + SERVICES=$(echo $PROMETHEUS_SERVICE_SCRAPE_TARGETS | tr "," "\n") + for SERVICE in ${SERVICES[@]} + do + cat $SG_CORE_DIR/devstack/prometheus-files/scrape_configs/$SERVICE >> $RESULT_CONFIG_FILE + done + + if [[ $PROMETHEUS_CUSTOM_SCRAPE_TARGETS != "" ]]; then + echo " - job_name: 'custom'" >> $RESULT_CONFIG_FILE + echo " static_configs:" >> $RESULT_CONFIG_FILE + echo " - targets: [$PROMETHEUS_CUSTOM_SCRAPE_TARGETS]" >> $RESULT_CONFIG_FILE + fi + + sudo mkdir -p `dirname $PROMETHEUS_CONF` + sudo cp $RESULT_CONFIG_FILE $PROMETHEUS_CONF + + sudo cp $SG_CORE_DIR/devstack/observabilityclient-files/prometheus.yaml /etc/openstack/prometheus.yaml +} + +function init_prometheus { + $SG_CORE_CONTAINER_EXECUTABLE run -v $PROMETHEUS_CONF:/etc/prometheus/prometheus.yml --network host --name prometheus -d $PROMETHEUS_CONTAINER_IMAGE --config.file=/etc/prometheus/prometheus.yml --web.enable-admin-api +} + + # check for service enabled if is_service_enabled sg-core; then - if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then - # Set up system services - echo_summary "Configuring system services sg-core" - preinstall_sg-core - - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - # Perform installation of service source - echo_summary "Installing sg-core" - install_sg-core - - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - # Configure after the other layer 1 and 2 services have been configured - echo_summary "Configuring sg-core" - configure_sg-core - - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - # Initialize and start the sg-core service - echo_summary "Initializing sg-core" - init_sg-core - fi - - if [[ "$1" == "unstack" ]]; then - $SG_CORE_CONTAINER_EXECUTABLE stop sg-core - $SG_CORE_CONTAINER_EXECUTABLE rm sg-core - fi - - if [[ "$1" == "clean" ]]; then - $SG_CORE_CONTAINER_EXECUTABLE rmi sg-core:latest - fi + mkdir $SG_CORE_WORKDIR + if [[ $SG_CORE_ENABLE = true ]]; then + if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then + # Set up system services + echo_summary "Configuring system services for sg-core" + install_container_executable + + elif [[ "$1" == "stack" && "$2" == "install" ]]; then + # Perform installation of service source + echo_summary "Installing sg-core" + install_sg-core + + elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then + # Configure after the other layer 1 and 2 services have been configured + echo_summary "Configuring sg-core" + configure_sg-core + + elif [[ "$1" == "stack" && "$2" == "extra" ]]; then + # Initialize and start the sg-core service + echo_summary "Initializing sg-core" + init_sg-core + fi + + if [[ "$1" == "unstack" ]]; then + $SG_CORE_CONTAINER_EXECUTABLE stop sg-core + $SG_CORE_CONTAINER_EXECUTABLE rm sg-core + fi + + if [[ "$1" == "clean" ]]; then + $SG_CORE_CONTAINER_EXECUTABLE rmi $SG_CORE_CONTAINER_IMAGE + fi + fi + if [[ $PROMETHEUS_ENABLE = true ]]; then + if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then + # Set up system services + echo_summary "Configuring system services prometheus" + install_container_executable + + elif [[ "$1" == "stack" && "$2" == "install" ]]; then + # Perform installation of service source + echo_summary "Installing prometheus" + install_prometheus + + elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then + # Configure after the other layer 1 and 2 services have been configured + echo_summary "Configuring prometheus" + configure_prometheus + + elif [[ "$1" == "stack" && "$2" == "extra" ]]; then + # Initialize and start the prometheus service + echo_summary "Initializing prometheus" + init_prometheus + fi + + if [[ "$1" == "unstack" ]]; then + $PROMETHEUS_CONTAINER_EXECUTABLE stop prometheus + $PROMETHEUS_CONTAINER_EXECUTABLE rm prometheus + fi + + if [[ "$1" == "clean" ]]; then + $PROMETHEUS_CONTAINER_EXECUTABLE rmi $PROMETHEUS_CONTAINER_IMAGE + fi + + fi + rm -rf $SG_CORE_WORKDIR fi diff --git a/devstack/prometheus-files/prometheus.yml b/devstack/prometheus-files/prometheus.yml new file mode 100644 index 00000000..b0f3377c --- /dev/null +++ b/devstack/prometheus-files/prometheus.yml @@ -0,0 +1,4 @@ +global: + scrape_interval: 15s # By default, scrape targets every 15 seconds. + +scrape_configs: diff --git a/devstack/prometheus-files/scrape_configs/prometheus b/devstack/prometheus-files/scrape_configs/prometheus new file mode 100644 index 00000000..04148a41 --- /dev/null +++ b/devstack/prometheus-files/scrape_configs/prometheus @@ -0,0 +1,4 @@ + - job_name: 'prometheus' + + static_configs: + - targets: ['localhost:9090'] diff --git a/devstack/prometheus-files/scrape_configs/sg-core b/devstack/prometheus-files/scrape_configs/sg-core new file mode 100644 index 00000000..2f7229dc --- /dev/null +++ b/devstack/prometheus-files/scrape_configs/sg-core @@ -0,0 +1,4 @@ + - job_name: 'sg-core' + + static_configs: + - targets: ['localhost:3000'] diff --git a/devstack/settings b/devstack/settings index 3e00b4c4..b44f8dbb 100644 --- a/devstack/settings +++ b/devstack/settings @@ -3,12 +3,36 @@ plugin_requires sg-core ceilometer enable_service sg-core enable_service ceilometer +### sg-core ### +SG_CORE_ENABLE=${SG_CORE_ENABLE:-true} + SG_CORE_DIR=$DEST/sg-core SG_CORE_CONF_DIR=/etc/sg-core SG_CORE_CONF=$SG_CORE_CONF_DIR/sg-core.conf.yaml +SG_CORE_WORKDIR=$SG_CORE_DIR/devstack/workdir SG_CORE_CONTAINER_REPOSITORY=${SG_CORE_CONTAINER_REPOSITORY:-quay.io/infrawatch/sg-core} SG_CORE_CONTAINER_TAG=${SG_CORE_CONTAINER_TAG:-latest} SG_CORE_CONTAINER_IMAGE=$SG_CORE_CONTAINER_REPOSITORY:$SG_CORE_CONTAINER_TAG SG_CORE_CONTAINER_EXECUTABLE="podman" + +### prometheus ### +PROMETHEUS_ENABLE=${PROMETHEUS_ENABLE:-true} + +PROMETHEUS_CONF_DIR=/etc/prometheus +PROMETHEUS_CONF=$PROMETHEUS_CONF_DIR/prometheus.yml + +PROMETHEUS_CONTAINER_REPOSITORY=${PROMETHEUS_CONTAINER_REPOSITORY:-quay.io/prometheus/prometheus} +PROMETHEUS_CONTAINER_TAG=${PROMETHEUS_CONTAINER_TAG:-latest} +PROMETHEUS_CONTAINER_IMAGE=$PROMETHEUS_CONTAINER_REPOSITORY:$PROMETHEUS_CONTAINER_TAG + +# It's assumed, that each service scrape target has its own same named +# file in the scrape_configs folder +# List of "," delimited names +# Currently supported values are "sg-core" and "prometheus" +PROMETHEUS_SERVICE_SCRAPE_TARGETS=${PROMETHEUS_SERVICE_SCRAPE_TARGETS:="sg-core"} + +# List of "," delimited targets. Each target is : +PROMETHEUS_CUSTOM_SCRAPE_TARGETS=${PROMETHEUS_CUSTOM_SCRAPE_TARGETS:-""} + diff --git a/devstack/sg-core.conf.yaml b/devstack/sg-core-files/sg-core.conf.yaml similarity index 100% rename from devstack/sg-core.conf.yaml rename to devstack/sg-core-files/sg-core.conf.yaml From f895c6fbf8bd6aabcd2646de3f617f9f83cb4d03 Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Thu, 16 Nov 2023 12:30:53 +0000 Subject: [PATCH 3/6] [zuul] Use the stf-crc-jobs project template (#122) Instead of updating the .zuul.yaml file everytime infrawatch/service-telemetry-operator adds a new job, the project-template can be updated in STO, which will propogate the change to the project and avoid leaving gaps in testing. Depends-On: https://github.com/infrawatch/service-telemetry-operator/pull/514 --- .zuul.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index b3f8da23..8e94b251 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,8 +1,5 @@ - --- - project: name: infrawatch/sg-core - github-check: - jobs: - - stf-crc-latest-nightly_bundles - - stf-crc-latest-local_build + templates: + - stf-crc-jobs From 4d514d5421c0624d615d93fdc8336655b4c55d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20Wysoglad?= Date: Thu, 23 Nov 2023 18:59:06 +0100 Subject: [PATCH 4/6] Add support for deploying with docker to devstack (#124) --- devstack/plugin.sh | 11 ++++++++++- devstack/settings | 2 -- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/devstack/plugin.sh b/devstack/plugin.sh index afef031c..9ed56074 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -1,5 +1,14 @@ function install_container_executable { - install_package $SG_CORE_CONTAINER_EXECUTABLE + if install_package podman; then + SG_CORE_CONTAINER_EXECUTABLE="podman" + elif install_package docker.io; then + sudo chown stack:docker /var/run/docker.sock + sudo usermod -aG docker stack + SG_CORE_CONTAINER_EXECUTABLE="docker" + else + echo_summary "Couldn't install podman or docker" + return 1 + fi if is_ubuntu; then install_package uidmap fi diff --git a/devstack/settings b/devstack/settings index b44f8dbb..da9722b7 100644 --- a/devstack/settings +++ b/devstack/settings @@ -15,8 +15,6 @@ SG_CORE_CONTAINER_REPOSITORY=${SG_CORE_CONTAINER_REPOSITORY:-quay.io/infrawatch/ SG_CORE_CONTAINER_TAG=${SG_CORE_CONTAINER_TAG:-latest} SG_CORE_CONTAINER_IMAGE=$SG_CORE_CONTAINER_REPOSITORY:$SG_CORE_CONTAINER_TAG -SG_CORE_CONTAINER_EXECUTABLE="podman" - ### prometheus ### PROMETHEUS_ENABLE=${PROMETHEUS_ENABLE:-true} From f7de9293732b6dc681a7f29b35caf5bb2f220a0b Mon Sep 17 00:00:00 2001 From: Yadnesh Kulkarni <24690448+yadneshk@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:12:20 +0530 Subject: [PATCH 5/6] Remove sg-core & prometheus containers with force Often times during unstack, containers get stuck in "Stopping" state and do not get cleaned up. These left over containers cause next run of stack.sh to fail because the script tries to spawn them with the name same. --- devstack/plugin.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 9ed56074..f390e431 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -90,7 +90,7 @@ if is_service_enabled sg-core; then if [[ "$1" == "unstack" ]]; then $SG_CORE_CONTAINER_EXECUTABLE stop sg-core - $SG_CORE_CONTAINER_EXECUTABLE rm sg-core + $SG_CORE_CONTAINER_EXECUTABLE rm -f sg-core fi if [[ "$1" == "clean" ]]; then @@ -121,7 +121,7 @@ if is_service_enabled sg-core; then if [[ "$1" == "unstack" ]]; then $PROMETHEUS_CONTAINER_EXECUTABLE stop prometheus - $PROMETHEUS_CONTAINER_EXECUTABLE rm prometheus + $PROMETHEUS_CONTAINER_EXECUTABLE rm -f prometheus fi if [[ "$1" == "clean" ]]; then From 35d6fbeac82fc3313f8d73bca28cf5fc6f18d5cf Mon Sep 17 00:00:00 2001 From: Chris Sibbitt Date: Tue, 19 Dec 2023 05:35:21 -0500 Subject: [PATCH 6/6] Move to golang 1.20 (#127) * Move to golang 1.20 * Bump golangci-lint to 1.51 for golang 1.20 support --- .github/workflows/tests.yml | 6 +++--- build/Dockerfile | 2 +- ci/integration/logging/run_sg.sh | 6 +++--- ci/integration/metrics/ceilometer/bridge/run_sg.sh | 6 +++--- ci/integration/metrics/ceilometer/tcp/run_sg.sh | 6 +++--- ci/integration/metrics/collectd/run_sg.sh | 6 +++--- ci/unit/run_tests.sh | 6 +++--- go.mod | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8cdbe3c3..d1a34cff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.20' - uses: actions/checkout@v3 #- name: download libraries # run: go mod download @@ -33,7 +33,7 @@ jobs: # Caching conflicts happen in GHA, so just disable for now skip-cache: true # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.50 + version: v1.51 unit-tests: name: Unit tests runs-on: ubuntu-20.04 @@ -78,7 +78,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: '1.19' + go-version: '1.20' - name: Verify image builds run: | docker build --tag infrawatch/sg-core:latest --file build/Dockerfile . diff --git a/build/Dockerfile b/build/Dockerfile index 946bf85f..c11c13b9 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -10,7 +10,7 @@ COPY . $D/ COPY build/repos/opstools.repo /etc/yum.repos.d/opstools.repo RUN dnf install golang git qpid-proton-c-devel -y --setopt=tsflags=nodocs -RUN go install golang.org/dl/go1.19@latest && /go/bin/go1.19 download && PRODUCTION_BUILD=false CONTAINER_BUILD=true GOCMD=/go/bin/go1.19 ./build.sh +RUN go install golang.org/dl/go1.20@latest && /go/bin/go1.20 download && PRODUCTION_BUILD=false CONTAINER_BUILD=true GOCMD=/go/bin/go1.20 ./build.sh # --- end build, create smart gateway layer --- FROM registry.access.redhat.com/ubi8-minimal:latest diff --git a/ci/integration/logging/run_sg.sh b/ci/integration/logging/run_sg.sh index c9c825a6..c6160aad 100644 --- a/ci/integration/logging/run_sg.sh +++ b/ci/integration/logging/run_sg.sh @@ -13,11 +13,11 @@ dnf install -y git golang gcc make qpid-proton-c-devel export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN -go install golang.org/dl/go1.19@latest -go1.19 download +go install golang.org/dl/go1.20@latest +go1.20 download # install sg-core and start sg-core mkdir -p /usr/lib64/sg-core -PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.19 BUILD_ARGS=-buildvcs=false ./build.sh +PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.20 BUILD_ARGS=-buildvcs=false ./build.sh ./sg-core -config ./ci/integration/logging/sg_config.yaml diff --git a/ci/integration/metrics/ceilometer/bridge/run_sg.sh b/ci/integration/metrics/ceilometer/bridge/run_sg.sh index a6bcb071..747d3362 100644 --- a/ci/integration/metrics/ceilometer/bridge/run_sg.sh +++ b/ci/integration/metrics/ceilometer/bridge/run_sg.sh @@ -13,11 +13,11 @@ dnf install -y git golang gcc make qpid-proton-c-devel export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN -go install golang.org/dl/go1.19@latest -go1.19 download +go install golang.org/dl/go1.20@latest +go1.20 download # install sg-core and start sg-core mkdir -p /usr/lib64/sg-core -PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.19 BUILD_ARGS=-buildvcs=false ./build.sh +PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.20 BUILD_ARGS=-buildvcs=false ./build.sh ./sg-core -config ./ci/integration/metrics/ceilometer/bridge/sg_config.yaml diff --git a/ci/integration/metrics/ceilometer/tcp/run_sg.sh b/ci/integration/metrics/ceilometer/tcp/run_sg.sh index 9ab3da08..1ef16839 100644 --- a/ci/integration/metrics/ceilometer/tcp/run_sg.sh +++ b/ci/integration/metrics/ceilometer/tcp/run_sg.sh @@ -13,11 +13,11 @@ dnf install -y git golang gcc make qpid-proton-c-devel export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN -go install golang.org/dl/go1.19@latest -go1.19 download +go install golang.org/dl/go1.20@latest +go1.20 download # install sg-core and start sg-core mkdir -p /usr/lib64/sg-core -PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.19 BUILD_ARGS=-buildvcs=false ./build.sh +PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.20 BUILD_ARGS=-buildvcs=false ./build.sh ./sg-core -config ./ci/integration/metrics/ceilometer/tcp/sg_config.yaml diff --git a/ci/integration/metrics/collectd/run_sg.sh b/ci/integration/metrics/collectd/run_sg.sh index 7e186cd0..ea1cd4cc 100644 --- a/ci/integration/metrics/collectd/run_sg.sh +++ b/ci/integration/metrics/collectd/run_sg.sh @@ -13,11 +13,11 @@ dnf install -y git golang gcc make qpid-proton-c-devel export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN -go install golang.org/dl/go1.19@latest -go1.19 download +go install golang.org/dl/go1.20@latest +go1.20 download # install sg-core and start sg-core mkdir -p /usr/lib64/sg-core -PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.19 BUILD_ARGS=-buildvcs=false ./build.sh +PLUGIN_DIR=/usr/lib64/sg-core/ GOCMD=go1.20 BUILD_ARGS=-buildvcs=false ./build.sh ./sg-core -config ./ci/integration/metrics/collectd/sg_config.yaml diff --git a/ci/unit/run_tests.sh b/ci/unit/run_tests.sh index 904d7113..83a4c92e 100644 --- a/ci/unit/run_tests.sh +++ b/ci/unit/run_tests.sh @@ -14,8 +14,8 @@ yum install -y git golang gcc make glibc-langpack-en qpid-proton-c-devel export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN -go install golang.org/dl/go1.19@latest -go1.19 download +go install golang.org/dl/go1.20@latest +go1.20 download -go1.19 test -v -coverprofile=profile.cov ./... +go1.20 test -v -coverprofile=profile.cov ./... diff --git a/go.mod b/go.mod index dc2ce1c4..8feab985 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/infrawatch/sg-core -go 1.19 +go 1.20 require ( collectd.org v0.5.0