From d00e875e34c6b7583d97c99fb6f808ee81e5c98e Mon Sep 17 00:00:00 2001 From: rubenruizdegauna Date: Fri, 12 May 2023 08:12:50 +0200 Subject: [PATCH] NR-91173 feat: fluent bit 2.x under FF (#1587) * NR-91173 feat: fluent bit 2.x under FF * add FB to al2023 amd64 * rename fb exe consts. clear vars in tests * NR-91173: add testLogger in ffhandler tests --------- Co-authored-by: Roger Coll --- build/goreleaser/linux/al2023_amd64.yml | 4 +- build/goreleaser/linux/al2023_arm.yml | 4 +- build/goreleaser/linux/al2023_arm64.yml | 2 +- build/goreleaser/linux/al2_amd64.yml | 3 +- build/goreleaser/linux/al2_arm.yml | 4 +- build/goreleaser/linux/al2_arm64.yml | 3 +- build/goreleaser/linux/centos_6_amd64.yml | 5 +- build/goreleaser/linux/centos_7_amd64.yml | 3 +- build/goreleaser/linux/centos_7_arm.yml | 5 +- build/goreleaser/linux/centos_7_arm64.yml | 3 +- build/goreleaser/linux/centos_8_amd64.yml | 3 +- build/goreleaser/linux/centos_8_arm.yml | 4 +- build/goreleaser/linux/centos_8_arm64.yml | 3 +- .../goreleaser/linux/debian_systemd_amd64.yml | 3 +- build/goreleaser/linux/debian_systemd_arm.yml | 4 +- .../goreleaser/linux/debian_systemd_arm64.yml | 3 +- .../goreleaser/linux/debian_upstart_amd64.yml | 3 +- build/goreleaser/linux/rhel_9_amd64.yml | 15 +- build/goreleaser/linux/rhel_9_arm.yml | 4 +- build/goreleaser/linux/rhel_9_arm64.yml | 13 +- build/goreleaser/linux/sles_114_amd64.yml | 4 +- build/goreleaser/linux/sles_121_amd64.yml | 3 +- build/goreleaser/linux/sles_122_amd64.yml | 3 +- build/goreleaser/linux/sles_122_arm.yml | 4 +- build/goreleaser/linux/sles_122_arm64.yml | 4 +- build/goreleaser/linux/sles_123_amd64.yml | 3 +- build/goreleaser/linux/sles_123_arm.yml | 4 +- build/goreleaser/linux/sles_123_arm64.yml | 4 +- build/goreleaser/linux/sles_124_amd64.yml | 3 +- build/goreleaser/linux/sles_124_arm.yml | 4 +- build/goreleaser/linux/sles_124_arm64.yml | 4 +- build/goreleaser/linux/sles_125_amd64.yml | 3 +- build/goreleaser/linux/sles_125_arm64.yml | 4 +- build/goreleaser/linux/sles_151_amd64.yml | 3 +- build/goreleaser/linux/sles_151_arm64.yml | 4 +- build/goreleaser/linux/sles_152_amd64.yml | 3 +- build/goreleaser/linux/sles_152_arm64.yml | 4 +- build/goreleaser/linux/sles_153_amd64.yml | 3 +- build/goreleaser/linux/sles_153_arm64.yml | 4 +- build/goreleaser/linux/sles_154_amd64.yml | 32 +-- build/goreleaser/linux/sles_154_arm64.yml | 4 +- cmd/newrelic-infra/newrelic-infra.go | 55 ++-- .../cmdchannel/fflag/fb_restarter_mock.go | 32 +++ internal/agent/cmdchannel/fflag/ffhandler.go | 58 +++- .../agent/cmdchannel/fflag/ffhandler_test.go | 213 ++++++++++++++- internal/feature_flags/feature_flags_mock.go | 24 ++ pkg/config/config.go | 12 - pkg/config/config_linux.go | 2 - pkg/config/config_windows.go | 2 - pkg/config/defaults.go | 2 - pkg/integrations/v4/README.md | 10 + pkg/integrations/v4/fb_1_vs_2_ff.png | Bin 0 -> 25392 bytes pkg/integrations/v4/manager_test.go | 3 +- pkg/integrations/v4/supervisor.go | 26 +- pkg/integrations/v4/supervisor_fb.go | 98 +++++-- .../v4/supervisor_fb_conf_linux.go | 33 +++ .../v4/supervisor_fb_conf_linux_test.go | 105 +++++++ .../v4/supervisor_fb_conf_others.go | 13 + .../v4/supervisor_fb_conf_windows.go | 28 ++ .../v4/supervisor_fb_conf_windows_test.go | 108 ++++++++ pkg/integrations/v4/supervisor_fb_test.go | 256 +++++++++++++++++- pkg/integrations/v4/supervisor_test.go | 2 +- .../ansible/installation-windows.yml | 16 +- test/packaging/ansible/log-forwarder.yml | 51 ++++ .../tasks/assert-version-Win32NT.yaml | 12 + .../roles/cleanup/tasks/files-Win32NT.yaml | 10 + .../roles/cleanup/tasks/package-Windows.yaml | 14 + .../roles/cleanup/tasks/service-Win32NT.yaml | 10 + .../ansible/roles/logging/tasks/main.yaml | 52 +--- .../multiple_version_assertion_Debian.yaml | 7 + .../multiple_version_assertion_RedHat.yaml | 7 + .../multiple_version_assertion_Suse.yaml | 5 + .../multiple_version_assertion_Win32NT.yaml | 15 + .../logging/tasks/process_running_Linux.yaml | 50 ++++ .../tasks/process_running_Win32NT.yaml | 15 + .../ansible/roles/logging/vars/main.yaml | 8 + .../tasks/package-Windows.yaml | 14 + test/packaging/ansible/test.yml | 3 + 78 files changed, 1340 insertions(+), 226 deletions(-) create mode 100644 internal/agent/cmdchannel/fflag/fb_restarter_mock.go create mode 100644 pkg/integrations/v4/README.md create mode 100644 pkg/integrations/v4/fb_1_vs_2_ff.png create mode 100644 pkg/integrations/v4/supervisor_fb_conf_linux.go create mode 100644 pkg/integrations/v4/supervisor_fb_conf_linux_test.go create mode 100644 pkg/integrations/v4/supervisor_fb_conf_others.go create mode 100644 pkg/integrations/v4/supervisor_fb_conf_windows.go create mode 100644 pkg/integrations/v4/supervisor_fb_conf_windows_test.go create mode 100644 test/packaging/ansible/roles/assert-version/tasks/assert-version-Win32NT.yaml create mode 100644 test/packaging/ansible/roles/cleanup/tasks/files-Win32NT.yaml create mode 100644 test/packaging/ansible/roles/cleanup/tasks/package-Windows.yaml create mode 100644 test/packaging/ansible/roles/cleanup/tasks/service-Win32NT.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Debian.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_RedHat.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Suse.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Win32NT.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/process_running_Linux.yaml create mode 100644 test/packaging/ansible/roles/logging/tasks/process_running_Win32NT.yaml create mode 100644 test/packaging/ansible/roles/package-uninstall/tasks/package-Windows.yaml diff --git a/build/goreleaser/linux/al2023_amd64.yml b/build/goreleaser/linux/al2023_amd64.yml index 26611966e..b9798d712 100644 --- a/build/goreleaser/linux/al2023_amd64.yml +++ b/build/goreleaser/linux/al2023_amd64.yml @@ -74,7 +74,7 @@ summary: "New Relic Infrastructure Agent" group: default # Required packages. rpm version 4.11.3 does not support weak dependencies -# recommends: -# - td-agent-bit + recommends: + - fluent-bit # end AL2023 adm64 diff --git a/build/goreleaser/linux/al2023_arm.yml b/build/goreleaser/linux/al2023_arm.yml index 9489072a2..93b19df05 100644 --- a/build/goreleaser/linux/al2023_arm.yml +++ b/build/goreleaser/linux/al2023_arm.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end AL2023 arm diff --git a/build/goreleaser/linux/al2023_arm64.yml b/build/goreleaser/linux/al2023_arm64.yml index e6db05b76..e3c10f1d6 100644 --- a/build/goreleaser/linux/al2023_arm64.yml +++ b/build/goreleaser/linux/al2023_arm64.yml @@ -72,6 +72,6 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# - fluent-bit # end AL2023 arm64 diff --git a/build/goreleaser/linux/al2_amd64.yml b/build/goreleaser/linux/al2_amd64.yml index 0a626c591..9a85e4dde 100644 --- a/build/goreleaser/linux/al2_amd64.yml +++ b/build/goreleaser/linux/al2_amd64.yml @@ -75,6 +75,7 @@ group: default # Required packages. rpm version 4.11.3 does not support weak dependencies dependencies: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end AL2 adm64 diff --git a/build/goreleaser/linux/al2_arm.yml b/build/goreleaser/linux/al2_arm.yml index 1347cbe6e..4b1e8cd7a 100644 --- a/build/goreleaser/linux/al2_arm.yml +++ b/build/goreleaser/linux/al2_arm.yml @@ -73,6 +73,8 @@ group: default # Required packages. rpm version 4.11.3 does not support weak dependencies # dependencies: -# - td-agent-bit + # FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end AL2 arm diff --git a/build/goreleaser/linux/al2_arm64.yml b/build/goreleaser/linux/al2_arm64.yml index 48e17310b..2abeadfde 100644 --- a/build/goreleaser/linux/al2_arm64.yml +++ b/build/goreleaser/linux/al2_arm64.yml @@ -72,6 +72,7 @@ group: default # Required packages. rpm version 4.11.3 does not support weak dependencies dependencies: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end AL2 arm64 diff --git a/build/goreleaser/linux/centos_6_amd64.yml b/build/goreleaser/linux/centos_6_amd64.yml index e108640f1..40b74f815 100644 --- a/build/goreleaser/linux/centos_6_amd64.yml +++ b/build/goreleaser/linux/centos_6_amd64.yml @@ -61,8 +61,9 @@ summary: "New Relic Infrastructure Agent" group: default # Required packages. rpm version 4.11.3 does not support weak dependencies. - # disabled as right now fb pkg is not built for centos-6 # dependencies: - # - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end CentOS 6 amd64 diff --git a/build/goreleaser/linux/centos_7_amd64.yml b/build/goreleaser/linux/centos_7_amd64.yml index 195842700..f81628e53 100644 --- a/build/goreleaser/linux/centos_7_amd64.yml +++ b/build/goreleaser/linux/centos_7_amd64.yml @@ -74,6 +74,7 @@ group: default # Required packages. rpm version 4.11.3 does not support weak dependencies dependencies: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end CentOS 7 amd64 diff --git a/build/goreleaser/linux/centos_7_arm.yml b/build/goreleaser/linux/centos_7_arm.yml index 9f0a859f0..efebbdc38 100644 --- a/build/goreleaser/linux/centos_7_arm.yml +++ b/build/goreleaser/linux/centos_7_arm.yml @@ -71,8 +71,9 @@ summary: "New Relic Infrastructure Agent" group: default # Required packages. rpm version 4.11.3 does not support weak dependencies - # disabled until logging packaging is properly handled for arm # dependencies: - # - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end CentOS 7 arm diff --git a/build/goreleaser/linux/centos_7_arm64.yml b/build/goreleaser/linux/centos_7_arm64.yml index 6d8c96693..96309f408 100644 --- a/build/goreleaser/linux/centos_7_arm64.yml +++ b/build/goreleaser/linux/centos_7_arm64.yml @@ -73,6 +73,7 @@ # Required packages. rpm version 4.11.3 does not support weak dependencies # disabled until logging packaging is properly handled for arm dependencies: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end CentOS 7 arm64 diff --git a/build/goreleaser/linux/centos_8_amd64.yml b/build/goreleaser/linux/centos_8_amd64.yml index 06daa17cd..2cf8e9ef9 100644 --- a/build/goreleaser/linux/centos_8_amd64.yml +++ b/build/goreleaser/linux/centos_8_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end CentOS 8 amd64 diff --git a/build/goreleaser/linux/centos_8_arm.yml b/build/goreleaser/linux/centos_8_arm.yml index adf5a1fb5..70e5cb2a9 100644 --- a/build/goreleaser/linux/centos_8_arm.yml +++ b/build/goreleaser/linux/centos_8_arm.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end CentOS 8 arm diff --git a/build/goreleaser/linux/centos_8_arm64.yml b/build/goreleaser/linux/centos_8_arm64.yml index 077fa624f..ad645f513 100644 --- a/build/goreleaser/linux/centos_8_arm64.yml +++ b/build/goreleaser/linux/centos_8_arm64.yml @@ -72,6 +72,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end CentOS 8 arm64 diff --git a/build/goreleaser/linux/debian_systemd_amd64.yml b/build/goreleaser/linux/debian_systemd_amd64.yml index 5637ebab4..9ba63d6c7 100644 --- a/build/goreleaser/linux/debian_systemd_amd64.yml +++ b/build/goreleaser/linux/debian_systemd_amd64.yml @@ -63,6 +63,7 @@ priority: extra # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end Debian systemd amd64 diff --git a/build/goreleaser/linux/debian_systemd_arm.yml b/build/goreleaser/linux/debian_systemd_arm.yml index e9d5d721c..ff6712048 100644 --- a/build/goreleaser/linux/debian_systemd_arm.yml +++ b/build/goreleaser/linux/debian_systemd_arm.yml @@ -63,6 +63,8 @@ priority: extra # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end Debian systemd arm diff --git a/build/goreleaser/linux/debian_systemd_arm64.yml b/build/goreleaser/linux/debian_systemd_arm64.yml index 9f41be8c6..144ac7c17 100644 --- a/build/goreleaser/linux/debian_systemd_arm64.yml +++ b/build/goreleaser/linux/debian_systemd_arm64.yml @@ -63,6 +63,7 @@ priority: extra # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end Debian systemd arm64 diff --git a/build/goreleaser/linux/debian_upstart_amd64.yml b/build/goreleaser/linux/debian_upstart_amd64.yml index 23d680496..a04acf2f0 100644 --- a/build/goreleaser/linux/debian_upstart_amd64.yml +++ b/build/goreleaser/linux/debian_upstart_amd64.yml @@ -59,6 +59,7 @@ priority: extra # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end Debian upstart amd64 diff --git a/build/goreleaser/linux/rhel_9_amd64.yml b/build/goreleaser/linux/rhel_9_amd64.yml index a9c752b70..30d0aa7f4 100644 --- a/build/goreleaser/linux/rhel_9_amd64.yml +++ b/build/goreleaser/linux/rhel_9_amd64.yml @@ -40,10 +40,10 @@ dst: '/var/db/newrelic-infra/newrelic-integrations/bin/nri-flex' - src: 'target/nriprometheus/amd64/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' dst: '/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' -# - src: 'target/fluent-bit-plugin/amd64/out_newrelic.so' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' -# - src: 'assets/examples/logging/parsers.conf' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' + - src: 'target/fluent-bit-plugin/amd64/out_newrelic.so' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' + - src: 'assets/examples/logging/parsers.conf' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' empty_folders: - /var/db/newrelic-infra/custom-integrations - /var/db/newrelic-infra/integrations.d @@ -73,9 +73,8 @@ summary: "New Relic Infrastructure Agent" group: default - # Required packages. rpm version 4.11.3 does not support weak dependencies -# not supported yet -# dependencies: -# - td-agent-bit + # Recommended packages. If they fail to install installation of the agent will not be interrupted. + recommends: + - fluent-bit # end RHEL 9 amd64 diff --git a/build/goreleaser/linux/rhel_9_arm.yml b/build/goreleaser/linux/rhel_9_arm.yml index b79ea2a7f..fd7f99fb6 100644 --- a/build/goreleaser/linux/rhel_9_arm.yml +++ b/build/goreleaser/linux/rhel_9_arm.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end RHEL 9 arm diff --git a/build/goreleaser/linux/rhel_9_arm64.yml b/build/goreleaser/linux/rhel_9_arm64.yml index 9ff1f1bbc..d44553db5 100644 --- a/build/goreleaser/linux/rhel_9_arm64.yml +++ b/build/goreleaser/linux/rhel_9_arm64.yml @@ -40,10 +40,10 @@ dst: '/var/db/newrelic-infra/newrelic-integrations/bin/nri-flex' - src: 'target/nriprometheus/{{ .Arch }}/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' dst: '/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' -# - src: 'target/fluent-bit-plugin/{{ .Arch }}/out_newrelic.so' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' -# - src: 'assets/examples/logging/parsers.conf' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' + - src: 'target/fluent-bit-plugin/{{ .Arch }}/out_newrelic.so' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' + - src: 'assets/examples/logging/parsers.conf' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' empty_folders: - /var/db/newrelic-infra/custom-integrations - /var/db/newrelic-infra/integrations.d @@ -71,8 +71,7 @@ summary: "New Relic Infrastructure Agent" group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. -# not supported yet -# dependencies: -# - td-agent-bit + recommends: + - fluent-bit # end RHEL 9 arm64 diff --git a/build/goreleaser/linux/sles_114_amd64.yml b/build/goreleaser/linux/sles_114_amd64.yml index c52ce2a37..836b27f4d 100644 --- a/build/goreleaser/linux/sles_114_amd64.yml +++ b/build/goreleaser/linux/sles_114_amd64.yml @@ -57,6 +57,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end SLES 11.4 amd64 diff --git a/build/goreleaser/linux/sles_121_amd64.yml b/build/goreleaser/linux/sles_121_amd64.yml index cac3d0b67..3b05f581e 100644 --- a/build/goreleaser/linux/sles_121_amd64.yml +++ b/build/goreleaser/linux/sles_121_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 12.1 amd64 diff --git a/build/goreleaser/linux/sles_122_amd64.yml b/build/goreleaser/linux/sles_122_amd64.yml index 0ca6f6340..5f35d20dd 100644 --- a/build/goreleaser/linux/sles_122_amd64.yml +++ b/build/goreleaser/linux/sles_122_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 12.2 amd64 diff --git a/build/goreleaser/linux/sles_122_arm.yml b/build/goreleaser/linux/sles_122_arm.yml index 57b0c42ba..40c73526e 100644 --- a/build/goreleaser/linux/sles_122_arm.yml +++ b/build/goreleaser/linux/sles_122_arm.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end SLES 12.2 arm diff --git a/build/goreleaser/linux/sles_122_arm64.yml b/build/goreleaser/linux/sles_122_arm64.yml index a3211e548..19ede80e4 100644 --- a/build/goreleaser/linux/sles_122_arm64.yml +++ b/build/goreleaser/linux/sles_122_arm64.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end SLES 12.2 arm64 diff --git a/build/goreleaser/linux/sles_123_amd64.yml b/build/goreleaser/linux/sles_123_amd64.yml index d370b0f98..5ae97afbc 100644 --- a/build/goreleaser/linux/sles_123_amd64.yml +++ b/build/goreleaser/linux/sles_123_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 12.3 amd64 diff --git a/build/goreleaser/linux/sles_123_arm.yml b/build/goreleaser/linux/sles_123_arm.yml index acc5484d1..92668b5e6 100644 --- a/build/goreleaser/linux/sles_123_arm.yml +++ b/build/goreleaser/linux/sles_123_arm.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 12.3 arm diff --git a/build/goreleaser/linux/sles_123_arm64.yml b/build/goreleaser/linux/sles_123_arm64.yml index bb066d36a..f815a2849 100644 --- a/build/goreleaser/linux/sles_123_arm64.yml +++ b/build/goreleaser/linux/sles_123_arm64.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 12.3 arm64 diff --git a/build/goreleaser/linux/sles_124_amd64.yml b/build/goreleaser/linux/sles_124_amd64.yml index e966b222c..8a4dac7c5 100644 --- a/build/goreleaser/linux/sles_124_amd64.yml +++ b/build/goreleaser/linux/sles_124_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 12.4 amd64 diff --git a/build/goreleaser/linux/sles_124_arm.yml b/build/goreleaser/linux/sles_124_arm.yml index 1334ac2af..171858749 100644 --- a/build/goreleaser/linux/sles_124_arm.yml +++ b/build/goreleaser/linux/sles_124_arm.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 12.4 arm diff --git a/build/goreleaser/linux/sles_124_arm64.yml b/build/goreleaser/linux/sles_124_arm64.yml index 42be7137c..188223364 100644 --- a/build/goreleaser/linux/sles_124_arm64.yml +++ b/build/goreleaser/linux/sles_124_arm64.yml @@ -72,6 +72,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 12.4 arm64 diff --git a/build/goreleaser/linux/sles_125_amd64.yml b/build/goreleaser/linux/sles_125_amd64.yml index 3d3e86987..9cb0bda87 100644 --- a/build/goreleaser/linux/sles_125_amd64.yml +++ b/build/goreleaser/linux/sles_125_amd64.yml @@ -77,6 +77,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 12.5 amd64 diff --git a/build/goreleaser/linux/sles_125_arm64.yml b/build/goreleaser/linux/sles_125_arm64.yml index 0447a04de..4131970a1 100644 --- a/build/goreleaser/linux/sles_125_arm64.yml +++ b/build/goreleaser/linux/sles_125_arm64.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 12.5 arm64 diff --git a/build/goreleaser/linux/sles_151_amd64.yml b/build/goreleaser/linux/sles_151_amd64.yml index be2fc00ee..9d862b8e5 100644 --- a/build/goreleaser/linux/sles_151_amd64.yml +++ b/build/goreleaser/linux/sles_151_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 15.1 amd64 diff --git a/build/goreleaser/linux/sles_151_arm64.yml b/build/goreleaser/linux/sles_151_arm64.yml index 970511611..fdbbb2974 100644 --- a/build/goreleaser/linux/sles_151_arm64.yml +++ b/build/goreleaser/linux/sles_151_arm64.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 15.1 arm64 diff --git a/build/goreleaser/linux/sles_152_amd64.yml b/build/goreleaser/linux/sles_152_amd64.yml index 83edbf4df..ebd4c061e 100644 --- a/build/goreleaser/linux/sles_152_amd64.yml +++ b/build/goreleaser/linux/sles_152_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 15.2 amd64 diff --git a/build/goreleaser/linux/sles_152_arm64.yml b/build/goreleaser/linux/sles_152_arm64.yml index e5e4c46d9..e047b4599 100644 --- a/build/goreleaser/linux/sles_152_arm64.yml +++ b/build/goreleaser/linux/sles_152_arm64.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 15.2 arm64 diff --git a/build/goreleaser/linux/sles_153_amd64.yml b/build/goreleaser/linux/sles_153_amd64.yml index 44e26903c..6affb4ac2 100644 --- a/build/goreleaser/linux/sles_153_amd64.yml +++ b/build/goreleaser/linux/sles_153_amd64.yml @@ -75,6 +75,7 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. recommends: - - td-agent-bit + - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + - fluent-bit # end SLES 15.3 amd64 diff --git a/build/goreleaser/linux/sles_153_arm64.yml b/build/goreleaser/linux/sles_153_arm64.yml index 1cc3c6660..4cadbc67b 100644 --- a/build/goreleaser/linux/sles_153_arm64.yml +++ b/build/goreleaser/linux/sles_153_arm64.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit + # FB not supported yet + # - td-agent-bit #To be removed on removal of the ff fluent_bit_19 + # - fluent-bit # end SLES 15.3 arm64 diff --git a/build/goreleaser/linux/sles_154_amd64.yml b/build/goreleaser/linux/sles_154_amd64.yml index 8e9ef0c6c..e7fae1c04 100644 --- a/build/goreleaser/linux/sles_154_amd64.yml +++ b/build/goreleaser/linux/sles_154_amd64.yml @@ -31,20 +31,20 @@ - src: 'target/nriprometheus/amd64/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' dst: '/var/db/newrelic-infra/newrelic-integrations/bin/nri-prometheus' -# - src: 'assets/examples/logging/linux/file.yml.example' -# dst: '/etc/newrelic-infra/logging.d/file.yml.example' -# - src: 'assets/examples/logging/linux/fluentbit.yml.example' -# dst: '/etc/newrelic-infra/logging.d/fluentbit.yml.example' -# - src: 'assets/examples/logging/linux/syslog.yml.example' -# dst: '/etc/newrelic-infra/logging.d/syslog.yml.example' -# - src: 'assets/examples/logging/linux/systemd.yml.example' -# dst: '/etc/newrelic-infra/logging.d/systemd.yml.example' -# - src: 'assets/examples/logging/linux/tcp.yml.example' -# dst: '/etc/newrelic-infra/logging.d/tcp.yml.example' -# - src: 'target/fluent-bit-plugin/amd64/out_newrelic.so' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' -# - src: 'assets/examples/logging/parsers.conf' -# dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' + - src: 'assets/examples/logging/linux/file.yml.example' + dst: '/etc/newrelic-infra/logging.d/file.yml.example' + - src: 'assets/examples/logging/linux/fluentbit.yml.example' + dst: '/etc/newrelic-infra/logging.d/fluentbit.yml.example' + - src: 'assets/examples/logging/linux/syslog.yml.example' + dst: '/etc/newrelic-infra/logging.d/syslog.yml.example' + - src: 'assets/examples/logging/linux/systemd.yml.example' + dst: '/etc/newrelic-infra/logging.d/systemd.yml.example' + - src: 'assets/examples/logging/linux/tcp.yml.example' + dst: '/etc/newrelic-infra/logging.d/tcp.yml.example' + - src: 'target/fluent-bit-plugin/amd64/out_newrelic.so' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/out_newrelic.so' + - src: 'assets/examples/logging/parsers.conf' + dst: '/var/db/newrelic-infra/newrelic-integrations/logging/parsers.conf' empty_folders: - /var/db/newrelic-infra/custom-integrations - /var/db/newrelic-infra/integrations.d @@ -74,7 +74,7 @@ summary: "New Relic Infrastructure Agent" group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. -# recommends: -# - td-agent-bit + recommends: + - fluent-bit # end SLES 15.4 amd64 diff --git a/build/goreleaser/linux/sles_154_arm64.yml b/build/goreleaser/linux/sles_154_arm64.yml index 584fdbf22..4654403cc 100644 --- a/build/goreleaser/linux/sles_154_arm64.yml +++ b/build/goreleaser/linux/sles_154_arm64.yml @@ -73,6 +73,8 @@ group: default # Recommended packages. If they fail to install installation of the agent will not be interrupted. # recommends: -# - td-agent-bit +# FB not supported yet +# - td-agent-bit #To be removed on removal of the ff fluent_bit_19 +# - fluent-bit # end SLES 15.4 arm64 diff --git a/cmd/newrelic-infra/newrelic-infra.go b/cmd/newrelic-infra/newrelic-infra.go index 3719ac433..5ca46370d 100644 --- a/cmd/newrelic-infra/newrelic-infra.go +++ b/cmd/newrelic-infra/newrelic-infra.go @@ -24,49 +24,46 @@ import ( "github.com/sirupsen/logrus" "github.com/newrelic/infrastructure-agent/cmd/newrelic-infra/dnschecks" - "github.com/newrelic/infrastructure-agent/pkg/disk" - "github.com/newrelic/infrastructure-agent/pkg/helpers" - http2 "github.com/newrelic/infrastructure-agent/pkg/http" - logFilter "github.com/newrelic/infrastructure-agent/pkg/log/filter" - "github.com/newrelic/infrastructure-agent/pkg/sysinfo/cloud" - "github.com/newrelic/infrastructure-agent/pkg/sysinfo/hostname" - - selfInstrumentation "github.com/newrelic/infrastructure-agent/internal/agent/instrumentation" - "github.com/newrelic/infrastructure-agent/internal/httpapi" - "github.com/newrelic/infrastructure-agent/internal/instrumentation" - + "github.com/newrelic/infrastructure-agent/cmd/newrelic-infra/initialize" + "github.com/newrelic/infrastructure-agent/internal/agent" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel" ccBackoff "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/backoff" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/fflag" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/runintegration" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/service" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/stopintegration" + selfInstrumentation "github.com/newrelic/infrastructure-agent/internal/agent/instrumentation" "github.com/newrelic/infrastructure-agent/internal/agent/status" + "github.com/newrelic/infrastructure-agent/internal/feature_flags" + "github.com/newrelic/infrastructure-agent/internal/httpapi" + "github.com/newrelic/infrastructure-agent/internal/instrumentation" "github.com/newrelic/infrastructure-agent/internal/integrations/v4/files" "github.com/newrelic/infrastructure-agent/internal/integrations/v4/integration" "github.com/newrelic/infrastructure-agent/internal/integrations/v4/v3legacy" "github.com/newrelic/infrastructure-agent/internal/socketapi" - "github.com/newrelic/infrastructure-agent/pkg/integrations/configrequest" - "github.com/newrelic/infrastructure-agent/pkg/integrations/track" - "github.com/newrelic/infrastructure-agent/pkg/plugins" - - "github.com/newrelic/infrastructure-agent/cmd/newrelic-infra/initialize" - "github.com/newrelic/infrastructure-agent/internal/agent" - "github.com/newrelic/infrastructure-agent/internal/feature_flags" "github.com/newrelic/infrastructure-agent/pkg/backend/backoff" "github.com/newrelic/infrastructure-agent/pkg/backend/commandapi" backendhttp "github.com/newrelic/infrastructure-agent/pkg/backend/http" "github.com/newrelic/infrastructure-agent/pkg/backend/identityapi" "github.com/newrelic/infrastructure-agent/pkg/config" + "github.com/newrelic/infrastructure-agent/pkg/disk" "github.com/newrelic/infrastructure-agent/pkg/fs/systemd" + "github.com/newrelic/infrastructure-agent/pkg/helpers" "github.com/newrelic/infrastructure-agent/pkg/helpers/recover" + http2 "github.com/newrelic/infrastructure-agent/pkg/http" + "github.com/newrelic/infrastructure-agent/pkg/integrations/configrequest" "github.com/newrelic/infrastructure-agent/pkg/integrations/legacy" + "github.com/newrelic/infrastructure-agent/pkg/integrations/track" v4 "github.com/newrelic/infrastructure-agent/pkg/integrations/v4" integrationsConfig "github.com/newrelic/infrastructure-agent/pkg/integrations/v4/config" "github.com/newrelic/infrastructure-agent/pkg/integrations/v4/dm" "github.com/newrelic/infrastructure-agent/pkg/integrations/v4/emitter" "github.com/newrelic/infrastructure-agent/pkg/integrations/v4/logs" wlog "github.com/newrelic/infrastructure-agent/pkg/log" + logFilter "github.com/newrelic/infrastructure-agent/pkg/log/filter" + "github.com/newrelic/infrastructure-agent/pkg/plugins" + "github.com/newrelic/infrastructure-agent/pkg/sysinfo/cloud" + "github.com/newrelic/infrastructure-agent/pkg/sysinfo/hostname" ) var ( @@ -464,14 +461,19 @@ func initializeAgentAndRun(c *config.Config, logFwCfg config.LogForward) error { os.Exit(1) } - // log-forwarder - fbIntCfg := v4.FBSupervisorConfig{ - FluentBitExePath: c.FluentBitExePath, - FluentBitNRLibPath: c.FluentBitNRLibPath, - FluentBitParsersPath: c.FluentBitParsersPath, - FluentBitVerbose: c.Log.Level == config.LogLevelTrace && c.Log.HasIncludeFilter(config.TracesFieldName, config.SupervisorTrace), - ConfTemporaryFolder: filepath.Join(c.AgentTempDir, v4.FbConfTempFolderNameDefault), - } + fbVerbose := c.Log.Level == config.LogLevelTrace && c.Log.HasIncludeFilter(config.TracesFieldName, config.SupervisorTrace) + confTempFolder := filepath.Join(c.AgentTempDir, v4.FbConfTempFolderNameDefault) + fbIntCfg := v4.NewFBSupervisorConfig( + ffManager, + c.AgentDir, + config.DefaultIntegrationsDir, + c.LoggingBinDir, + c.FluentBitExePath, + c.FluentBitNRLibPath, + c.FluentBitParsersPath, + fbVerbose, + confTempFolder, + ) if fbIntCfg.IsLogForwarderAvailable() { logCfgLoader := logs.NewFolderLoader(logFwCfg, agt.Context.Identity, agt.Context.HostnameResolver()) @@ -482,6 +484,7 @@ func initializeAgentAndRun(c *config.Config, logFwCfg config.LogForward) error { agt.Context.HostnameChangeNotifier(), agt.Context.SendEvent, ) + ffHandle.SetFBRestarter(logSupervisor) go logSupervisor.Run(agt.Context.Ctx) } else { aslog.Debug("Log forwarder is not available for this platform. The agent will start without log forwarding support.") diff --git a/internal/agent/cmdchannel/fflag/fb_restarter_mock.go b/internal/agent/cmdchannel/fflag/fb_restarter_mock.go new file mode 100644 index 000000000..7ccc9cb63 --- /dev/null +++ b/internal/agent/cmdchannel/fflag/fb_restarter_mock.go @@ -0,0 +1,32 @@ +/* + * Copyright 2021 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package fflag + +import "github.com/stretchr/testify/mock" + +type FBRestarterMock struct { + mock.Mock +} + +func (f *FBRestarterMock) Restart() error { + fArgs := f.Called() + + return fArgs.Error(0) //nolint:wrapcheck +} + +func (f *FBRestarterMock) ShouldReturnNoError() { + f. + On("Restart"). + Once(). + Return(nil) +} + +func (f *FBRestarterMock) ShouldReturnError(err error) { + f. + On("Restart"). + Once(). + Return(err) +} diff --git a/internal/agent/cmdchannel/fflag/ffhandler.go b/internal/agent/cmdchannel/fflag/ffhandler.go index faf93fcca..038a51d80 100644 --- a/internal/agent/cmdchannel/fflag/ffhandler.go +++ b/internal/agent/cmdchannel/fflag/ffhandler.go @@ -5,6 +5,7 @@ package fflag import ( "context" "encoding/json" + "errors" "os" "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel" @@ -44,11 +45,12 @@ type args struct { // handler handles FF commands. type handler struct { - cfg *config.Config - ohiEnabler OHIEnabler - ffSetter feature_flags.Setter - ffsState handledStatePerFF - logger log.Entry + cfg *config.Config + ohiEnabler OHIEnabler + fbRestarter FBRestarter + ffSetter feature_flags.Setter + ffsState handledStatePerFF + logger log.Entry } // OHIEnabler enables or disables an OHI via cmd-channel feature flag. @@ -57,6 +59,10 @@ type OHIEnabler interface { DisableOHIFromFF(featureFlag string) error } +type FBRestarter interface { + Restart() error +} + // represents the state of an FF: non handled, handled to enable, handled to disable or both. type ffHandledState uint @@ -116,6 +122,12 @@ func (h *handler) SetOHIHandler(e OHIEnabler) { h.ohiEnabler = e } +// SetFBRestarter injects the handler dependency. A proper refactor of agent services injection will +// be required for this to be injected via srv constructor. +func (h *handler) SetFBRestarter(fbr FBRestarter) { + h.fbRestarter = fbr +} + func (h *handler) Handle(ctx context.Context, c commandapi.Command, isInitialFetch bool) (err error) { var ffArgs args if err = json.Unmarshal(c.Args, &ffArgs); err != nil { @@ -139,8 +151,8 @@ func (h *handler) Handle(ctx context.Context, c commandapi.Command, isInitialFet } if ffArgs.Flag == FlagFluentBit19 { - // FluentBit 1.9 Feature Flag is not merged yet, but it's created in the Backend so we need to take it - // into account and do nothing not to be trated as an OHI FF. + h.handleFBRestart(ffArgs) + return } @@ -249,6 +261,38 @@ func handleParallelizeInventory(ffArgs args, c *config.Config, isInitialFetch bo } } +func (h *handler) handleFBRestart(ffArgs args) { + err := h.ffSetter.SetFeatureFlag(ffArgs.Flag, ffArgs.Enabled) + if err != nil { + // ignore if the FF has been already set + if errors.Is(err, feature_flags.ErrFeatureFlagAlreadyExists) { + return + } + + ffLogger. + WithError(err). + WithField("feature_flag", ffArgs.Flag). + WithField("enable", ffArgs.Enabled). + Debug("Cannot set feature flag configuration.") + + return + } + + if h.fbRestarter == nil { + ffLogger.Debug("No fbRestarter for cmd feature request.") + + return + } + + err = h.fbRestarter.Restart() + if err != nil { + ffLogger. + WithError(err). + WithField("enabled", ffArgs.Enabled). + Debug("Unable to restart fb") + } +} + func handleRegister(ffArgs args, c *config.Config, isInitialFetch bool) { if ffArgs.Enabled == c.RegisterEnabled { return diff --git a/internal/agent/cmdchannel/fflag/ffhandler_test.go b/internal/agent/cmdchannel/fflag/ffhandler_test.go index dae5bd425..c82cf1d64 100644 --- a/internal/agent/cmdchannel/fflag/ffhandler_test.go +++ b/internal/agent/cmdchannel/fflag/ffhandler_test.go @@ -4,6 +4,7 @@ package fflag import ( "context" + "errors" "fmt" "os" "os/exec" @@ -18,11 +19,17 @@ import ( "github.com/newrelic/infrastructure-agent/pkg/backend/commandapi" "github.com/newrelic/infrastructure-agent/pkg/config" "github.com/newrelic/infrastructure-agent/pkg/log" + log2 "github.com/newrelic/infrastructure-agent/test/log" + + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) +//nolint:gochecknoglobals var ( - l = log.WithComponent("test") + testLogger = log.WithComponent("test") + errForTest = errors.New("some error") ) func Test_ffHandledState_requestWasAlreadyLogged(t *testing.T) { @@ -51,7 +58,9 @@ func TestFFHandlerHandle_EnablesRegisterOnInitialFetch(t *testing.T) { "flag": "register_enabled", "enabled": true }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + + //nolint:errcheck + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.True(t, c.RegisterEnabled) } @@ -64,7 +73,9 @@ func TestFFHandlerHandle_DisablesRegisterOnInitialFetch(t *testing.T) { "flag": "register_enabled", "enabled": false }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + + //nolint:errcheck + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.False(t, c.RegisterEnabled) } @@ -79,7 +90,9 @@ func TestFFHandlerHandle_DisablesParallelizeInventoryConfigOnInitialFetch(t *tes "flag": "parallelize_inventory_enabled", "enabled": false }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + + //nolint:errcheck + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.Equal(t, 0, c.InventoryQueueLen) } @@ -92,7 +105,9 @@ func TestFFHandlerHandle_EnablesParallelizeInventoryConfigWithDefaultValue(t *te "flag": "parallelize_inventory_enabled", "enabled": true }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + + //nolint:errcheck + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.Equal(t, CfgValueParallelizeInventory, int64(c.InventoryQueueLen)) } @@ -107,7 +122,9 @@ func TestFFHandlerHandle_EnabledFFParallelizeInventoryDoesNotModifyProvidedConfi "flag": "parallelize_inventory_enabled", "enabled": true }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + + //nolint:errcheck + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.Equal(t, 123, c.InventoryQueueLen) } @@ -122,7 +139,7 @@ func TestFFHandlerHandle_AsyncInventoryHandlerEnabledInitialFetch(t *testing.T) "flag": "async_inventory_handler_enabled", "enabled": true }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.True(t, c.AsyncInventoryHandlerEnabled) } @@ -137,7 +154,7 @@ func TestFFHandlerHandle_AsyncInventoryHandlerEnabled(t *testing.T) { "flag": "async_inventory_handler_enabled", "enabled": true }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, false) + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, false) assert.True(t, c.AsyncInventoryHandlerEnabled) } @@ -152,7 +169,7 @@ func TestFFHandlerHandle_AsyncInventoryHandler_Disabled(t *testing.T) { "flag": "async_inventory_handler_enabled", "enabled": false }`), } - NewHandler(&c, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, true) + NewHandler(&c, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, true) assert.False(t, c.AsyncInventoryHandlerEnabled) } @@ -180,7 +197,9 @@ func TestFFHandlerHandle_ExitsOnDiffValueAndNotInitialFetch(t *testing.T) { "flag": "%s", "enabled": true }`, tc.ff)), } - NewHandler(&config.Config{}, feature_flags.NewManager(nil), l).Handle(context.Background(), cmd, false) + + //nolint:errcheck + NewHandler(&config.Config{}, feature_flags.NewManager(nil), testLogger).Handle(context.Background(), cmd, false) } cmd := exec.Command(os.Args[0], "-test.run=TestFFHandlerHandle_ExitsOnDiffValueAndNotInitialFetch") @@ -214,7 +233,7 @@ func TestSrv_InitialFetch_EnablesRegister(t *testing.T) { } ` c := config.Config{RegisterEnabled: false} - h := NewHandler(&c, feature_flags.NewManager(nil), l) + h := NewHandler(&c, feature_flags.NewManager(nil), testLogger) ffHandler := cmdchannel.NewCmdHandler("set_feature_flag", h.Handle) s := service.NewService(cmdchanneltest.SuccessClient(serializedCmds), 0, make(chan int, 1), ffHandler) @@ -241,7 +260,7 @@ func TestSrv_InitialFetch_DisablesRegister(t *testing.T) { } ` c := config.Config{RegisterEnabled: true} - h := NewHandler(&c, feature_flags.NewManager(nil), l) + h := NewHandler(&c, feature_flags.NewManager(nil), testLogger) ffHandler := cmdchannel.NewCmdHandler("set_feature_flag", h.Handle) s := service.NewService(cmdchanneltest.SuccessClient(serializedCmds), 0, make(chan int, 1), ffHandler) @@ -268,7 +287,7 @@ func TestSrv_InitialFetch_EnablesDimensionalMetrics(t *testing.T) { } ` ffManager := feature_flags.NewManager(nil) - h := NewHandler(&config.Config{}, ffManager, l) + h := NewHandler(&config.Config{}, ffManager, testLogger) ffHandler := cmdchannel.NewCmdHandler("set_feature_flag", h.Handle) s := service.NewService(cmdchanneltest.SuccessClient(serializedCmds), 0, make(chan int, 1), ffHandler) @@ -279,3 +298,171 @@ func TestSrv_InitialFetch_EnablesDimensionalMetrics(t *testing.T) { assert.True(t, exists) assert.True(t, enabled) } + +func TestSrv_InitialFetch_EnablesFb19(t *testing.T) { + t.Parallel() + + serializedCmds := ` + { + "return_value": [ + { + "id": 0, + "name": "set_feature_flag", + "arguments": { + "category": "Infra_Agent", + "flag": "fluent_bit_19", + "enabled": true + } + } + ] + } +` + ffManager := feature_flags.NewManager(nil) + h := NewHandler(&config.Config{}, ffManager, testLogger) + ffHandler := cmdchannel.NewCmdHandler("set_feature_flag", h.Handle) + s := service.NewService(cmdchanneltest.SuccessClient(serializedCmds), 0, make(chan int, 1), ffHandler) + + _, err := s.InitialFetch(context.Background()) + assert.NoError(t, err) + + enabled, exists := ffManager.GetFeatureFlag(FlagFluentBit19) + assert.True(t, exists) + assert.True(t, enabled) +} + +//nolint:paralleltest +func Test_handleFBRestart_NoRestarter(t *testing.T) { + ffRetriever := &feature_flags.FeatureFlagSetterMock{} + ffRetriever.ShouldReturnNoError(FlagFluentBit19) + + ffArgs := args{ + Category: FlagCategory, + Flag: FlagFluentBit19, + Enabled: false, + } + + hook := log2.NewInMemoryEntriesHook([]logrus.Level{logrus.DebugLevel}) + log.AddHook(hook) + log.SetLevel(logrus.DebugLevel) + + h := NewHandler(&config.Config{}, ffRetriever, testLogger) + h.handleFBRestart(ffArgs) + + entries := hook.GetEntries() + assert.Equal(t, "No fbRestarter for cmd feature request.", entries[0].Message) + + mock.AssertExpectationsForObjects(t, ffRetriever) +} + +//nolint:paralleltest +func Test_handleFBRestart_WithRestarterNoError(t *testing.T) { + ffRetriever := &feature_flags.FeatureFlagSetterMock{} + ffRetriever.ShouldReturnNoError(FlagFluentBit19) + + ffArgs := args{ + Category: FlagCategory, + Flag: FlagFluentBit19, + Enabled: false, + } + + hook := log2.NewInMemoryEntriesHook([]logrus.Level{logrus.DebugLevel}) + log.AddHook(hook) + log.SetLevel(logrus.DebugLevel) + + restarter := &FBRestarterMock{} + restarter.ShouldReturnNoError() + + h := NewHandler(&config.Config{}, ffRetriever, testLogger) + h.SetFBRestarter(restarter) + h.handleFBRestart(ffArgs) + + entries := hook.GetEntries() + assert.Len(t, entries, 0) + + mock.AssertExpectationsForObjects(t, ffRetriever, restarter) +} + +//nolint:paralleltest +func Test_handleFBRestart_WithRestarterError(t *testing.T) { + ffRetriever := &feature_flags.FeatureFlagSetterMock{} + ffRetriever.ShouldReturnNoError(FlagFluentBit19) + + ffArgs := args{ + Category: FlagCategory, + Flag: FlagFluentBit19, + Enabled: false, + } + + hook := log2.NewInMemoryEntriesHook([]logrus.Level{logrus.DebugLevel}) + log.AddHook(hook) + log.SetLevel(logrus.DebugLevel) + + restarter := &FBRestarterMock{} + restarter.ShouldReturnError(errForTest) + + h := NewHandler(&config.Config{}, ffRetriever, testLogger) + h.SetFBRestarter(restarter) + h.handleFBRestart(ffArgs) + + entries := hook.GetEntries() + assert.Equal(t, "Unable to restart fb", entries[0].Message) + assert.ErrorIs(t, errForTest, entries[0].Data["error"].(error)) //nolint:forcetypeassert + + mock.AssertExpectationsForObjects(t, ffRetriever, restarter) +} + +//nolint:paralleltest +func Test_handleFBRestart_FlagAlreadyExists(t *testing.T) { + ffRetriever := &feature_flags.FeatureFlagSetterMock{} + ffRetriever.ShouldReturnError(FlagFluentBit19, feature_flags.ErrFeatureFlagAlreadyExists) + + ffArgs := args{ + Category: FlagCategory, + Flag: FlagFluentBit19, + Enabled: false, + } + + hook := log2.NewInMemoryEntriesHook([]logrus.Level{logrus.DebugLevel}) + log.AddHook(hook) + log.SetLevel(logrus.DebugLevel) + + restarter := &FBRestarterMock{} + + h := NewHandler(&config.Config{}, ffRetriever, testLogger) + h.SetFBRestarter(restarter) + h.handleFBRestart(ffArgs) + + entries := hook.GetEntries() + assert.Len(t, entries, 0) + + mock.AssertExpectationsForObjects(t, ffRetriever, restarter) +} + +//nolint:paralleltest +func Test_handleFBRestart_FlagRetrieverError(t *testing.T) { + ffRetriever := &feature_flags.FeatureFlagSetterMock{} + ffRetriever.ShouldReturnError(FlagFluentBit19, errForTest) + + ffArgs := args{ + Category: FlagCategory, + Flag: FlagFluentBit19, + Enabled: false, + } + + hook := log2.NewInMemoryEntriesHook([]logrus.Level{logrus.DebugLevel}) + log.AddHook(hook) + log.SetLevel(logrus.DebugLevel) + + restarter := &FBRestarterMock{} + + h := NewHandler(&config.Config{}, ffRetriever, testLogger) + h.SetFBRestarter(restarter) + h.handleFBRestart(ffArgs) + + entries := hook.GetEntries() + assert.Len(t, entries, 1) + assert.Equal(t, "Cannot set feature flag configuration.", entries[0].Message) + assert.ErrorIs(t, errForTest, entries[0].Data["error"].(error)) //nolint:forcetypeassert + + mock.AssertExpectationsForObjects(t, ffRetriever, restarter) +} diff --git a/internal/feature_flags/feature_flags_mock.go b/internal/feature_flags/feature_flags_mock.go index 949dcde13..07ea94638 100644 --- a/internal/feature_flags/feature_flags_mock.go +++ b/internal/feature_flags/feature_flags_mock.go @@ -36,3 +36,27 @@ func (f *FeatureFlagRetrieverMock) ShouldNotGetFeatureFlag(name string) { Once(). Return(false, false) } + +type FeatureFlagSetterMock struct { + mock.Mock +} + +func (f *FeatureFlagSetterMock) SetFeatureFlag(name string, enabled bool) error { + args := f.Called(name, enabled) + + return args.Error(0) +} + +func (f *FeatureFlagSetterMock) ShouldReturnNoError(name string) { + f. + On("SetFeatureFlag", name, mock.Anything). + Once(). + Return(nil) +} + +func (f *FeatureFlagSetterMock) ShouldReturnError(name string, err error) { + f. + On("SetFeatureFlag", name, mock.Anything). + Once(). + Return(err) +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 1d5185978..29a53b141 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2167,18 +2167,6 @@ func NormalizeConfig(cfg *Config, cfgMetadata config_loader.YAMLMetadata) (err e cfg.LoggingConfigsDir = filepath.Join(cfg.ConfigDir, defaultLoggingConfigsDir) } - if cfg.LoggingBinDir == "" { - if runtime.GOOS == "linux" { - cfg.LoggingBinDir = defaultLoggingBinDir - } else if runtime.GOOS == "windows" { - cfg.LoggingBinDir = filepath.Join(cfg.AgentDir, DefaultIntegrationsDir, defaultLoggingBinDir) - } - } - - if cfg.FluentBitExePath == "" { - cfg.FluentBitExePath = filepath.Join(cfg.LoggingBinDir, defaultFluentBitExe) - } - if cfg.LoggingHomeDir == "" { cfg.LoggingHomeDir = filepath.Join(cfg.AgentDir, DefaultIntegrationsDir, defaultLoggingHomeDir) } diff --git a/pkg/config/config_linux.go b/pkg/config/config_linux.go index 9e7b05baa..2aedf8beb 100644 --- a/pkg/config/config_linux.go +++ b/pkg/config/config_linux.go @@ -37,10 +37,8 @@ func init() { "index-1": {"tun", "tap"}, } - defaultLoggingBinDir = "/opt/td-agent-bit/bin" defaultLoggingHomeDir = "logging" defaultLoggingConfigsDir = "logging.d" - defaultFluentBitExe = "td-agent-bit" defaultFluentBitParsers = "parsers.conf" defaultFluentBitNRLib = "out_newrelic.so" diff --git a/pkg/config/config_windows.go b/pkg/config/config_windows.go index 58607502e..293562071 100644 --- a/pkg/config/config_windows.go +++ b/pkg/config/config_windows.go @@ -61,11 +61,9 @@ func init() { defaultConfigFiles = []string{filepath.Join(defaultAgentDir, "newrelic-infra.yml")} defaultPluginConfigFiles = []string{filepath.Join(defaultAgentDir, "newrelic-infra-plugins.yml")} - defaultLoggingBinDir = "logging" defaultLoggingHomeDir = "logging" defaultLoggingConfigsDir = "logging.d" - defaultFluentBitExe = "fluent-bit.exe" defaultFluentBitParsers = "parsers.conf" defaultFluentBitNRLib = "out_newrelic.dll" diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 3c60f87fd..ab2aabecf 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -126,9 +126,7 @@ var ( defaultPluginInstanceDir string defaultConfigDir string defaultLoggingConfigsDir string - defaultLoggingBinDir string defaultLoggingHomeDir string - defaultFluentBitExe string defaultFluentBitParsers string defaultFluentBitNRLib string defaultIntegrationsTempDir string diff --git a/pkg/integrations/v4/README.md b/pkg/integrations/v4/README.md new file mode 100644 index 000000000..793e39d7a --- /dev/null +++ b/pkg/integrations/v4/README.md @@ -0,0 +1,10 @@ +### Fluentbit supervisor + +td-agent-bit is becoming fluent-bit in version 2.x, so the binary name and paths are changing. To prevent any issue +we will handle this under a Feature Flag. + +#### Update 2023-03-13 +This change will be only done for Windows for now as there is a bug present in FB 2.0.6 that is not fixed yet. The +changes needed for Windows will be left in a draft PR + +![fb_1_vs_2_ff.png](fb_1_vs_2_ff.png) \ No newline at end of file diff --git a/pkg/integrations/v4/fb_1_vs_2_ff.png b/pkg/integrations/v4/fb_1_vs_2_ff.png new file mode 100644 index 0000000000000000000000000000000000000000..ca47e64ab247903e76689008d468847f753d7cc4 GIT binary patch literal 25392 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.0). + defaultLoggingBinDir2 = "/opt/fluent-bit/bin" + defaultFluentBitExecutable2 = "fluent-bit" +) + +func (c *fBSupervisorConfig) defaultLoggingBinDir(ffExists bool, ffEnabled bool) string { + if ffExists && ffEnabled { + return defaultLoggingBinDir1 + } + + return defaultLoggingBinDir2 +} + +func (c *fBSupervisorConfig) defaultFluentBitExePath(ffExists bool, ffEnabled bool, loggingBinDir string) string { + defaultFluentBitExe := defaultFluentBitExecutable2 + if ffExists && ffEnabled { + defaultFluentBitExe = defaultFluentBitExecutable1 + } + + return filepath.Join(loggingBinDir, defaultFluentBitExe) +} diff --git a/pkg/integrations/v4/supervisor_fb_conf_linux_test.go b/pkg/integrations/v4/supervisor_fb_conf_linux_test.go new file mode 100644 index 000000000..f6755367e --- /dev/null +++ b/pkg/integrations/v4/supervisor_fb_conf_linux_test.go @@ -0,0 +1,105 @@ +// Copyright 2021 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +//go:build linux + +package v4 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_defaultLoggingBinDir(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + ffEnabled bool + ffExists bool + expectedBinDir string + }{ + { + name: "no ff", + ffExists: false, + expectedBinDir: "/opt/fluent-bit/bin", + }, + { + name: "no ff but enabled", + ffExists: false, + ffEnabled: true, + expectedBinDir: "/opt/fluent-bit/bin", + }, + { + name: "disabled ff", + ffExists: true, + ffEnabled: false, + expectedBinDir: "/opt/fluent-bit/bin", + }, + { + name: "enabled ff", + ffExists: true, + ffEnabled: true, + expectedBinDir: "/opt/td-agent-bit/bin", + }, + } + + cfg := fBSupervisorConfig{} + + for i := range testCases { + testCase := testCases[i] + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + binDir := cfg.defaultLoggingBinDir(testCase.ffExists, testCase.ffEnabled) + assert.Equal(t, testCase.expectedBinDir, binDir) + }) + } +} + +func Test_defaultFluentBitExePath(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + ffEnabled bool + ffExists bool + expectedExePath string + }{ + { + name: "no ff", + ffExists: false, + expectedExePath: "/opt/fluent-bit/bin/fluent-bit", + }, + { + name: "no ff but enabled", + ffExists: false, + ffEnabled: true, + expectedExePath: "/opt/fluent-bit/bin/fluent-bit", + }, + { + name: "disabled ff", + ffExists: true, + ffEnabled: false, + expectedExePath: "/opt/fluent-bit/bin/fluent-bit", + }, + { + name: "enabled ff", + ffExists: true, + ffEnabled: true, + expectedExePath: "/opt/td-agent-bit/bin/td-agent-bit", + }, + } + + cfg := fBSupervisorConfig{} + + for i := range testCases { + testCase := testCases[i] + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + loggingBinDir := cfg.defaultLoggingBinDir(testCase.ffExists, testCase.ffEnabled) + exePath := cfg.defaultFluentBitExePath(testCase.ffExists, testCase.ffEnabled, loggingBinDir) + assert.Equal(t, testCase.expectedExePath, exePath) + }) + } +} diff --git a/pkg/integrations/v4/supervisor_fb_conf_others.go b/pkg/integrations/v4/supervisor_fb_conf_others.go new file mode 100644 index 000000000..fb219744b --- /dev/null +++ b/pkg/integrations/v4/supervisor_fb_conf_others.go @@ -0,0 +1,13 @@ +// Copyright 2021 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +//go:build !linux && !windows + +package v4 + +func (c *fBSupervisorConfig) defaultLoggingBinDir(_ bool, _ bool) string { + return "" +} + +func (c *fBSupervisorConfig) defaultFluentBitExePath(_ bool, _ bool, _ string) string { + return "" +} diff --git a/pkg/integrations/v4/supervisor_fb_conf_windows.go b/pkg/integrations/v4/supervisor_fb_conf_windows.go new file mode 100644 index 000000000..76b00fb61 --- /dev/null +++ b/pkg/integrations/v4/supervisor_fb_conf_windows.go @@ -0,0 +1,28 @@ +// Copyright 2021 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +//go:build windows + +package v4 + +import "path/filepath" + +const ( + // defaults for td-agent-bit (<=1.9). + defaultLoggingBinDir1 = "logging" + // defaults for fluent-bit (>=2.0). + defaultLoggingBinDir2 = "logging" + // both versions have the same name. + defaultFluentBitExe = "fluent-bit.exe" +) + +func (c *fBSupervisorConfig) defaultLoggingBinDir(ffExists bool, ffEnabled bool) string { + loggingBinDir := defaultLoggingBinDir2 + if ffExists && ffEnabled { + loggingBinDir = defaultLoggingBinDir1 + } + return filepath.Join(c.agentDir, c.integrationsDir, loggingBinDir) +} + +func (c *fBSupervisorConfig) defaultFluentBitExePath(_ bool, _ bool, loggingBinDir string) string { + return filepath.Join(loggingBinDir, defaultFluentBitExe) +} diff --git a/pkg/integrations/v4/supervisor_fb_conf_windows_test.go b/pkg/integrations/v4/supervisor_fb_conf_windows_test.go new file mode 100644 index 000000000..f0bbe7e28 --- /dev/null +++ b/pkg/integrations/v4/supervisor_fb_conf_windows_test.go @@ -0,0 +1,108 @@ +// Copyright 2021 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +//go:build windows + +package v4 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_defaultLoggingBinDir(t *testing.T) { + agentDir := "C:\\some\\agent\\dir" + integrationsDir := "integrations_dir" + + testCases := []struct { + name string + ffEnabled bool + ffExists bool + expectedLoggingBinDir string + }{ + { + name: "no ff", + ffExists: false, + ffEnabled: false, + expectedLoggingBinDir: "C:\\some\\agent\\dir\\integrations_dir\\logging", + }, + { + name: "no ff but enabled", + ffExists: false, + ffEnabled: true, + expectedLoggingBinDir: "C:\\some\\agent\\dir\\integrations_dir\\logging", + }, + { + name: "disabled ff", + ffExists: true, + ffEnabled: false, + expectedLoggingBinDir: "C:\\some\\agent\\dir\\integrations_dir\\logging", + }, + { + name: "enabled ff", + ffExists: true, + ffEnabled: true, + expectedLoggingBinDir: "C:\\some\\agent\\dir\\integrations_dir\\logging", + }, + } + + cfg := fBSupervisorConfig{ + agentDir: agentDir, + integrationsDir: integrationsDir, + } + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + loggingBinDir := cfg.defaultLoggingBinDir(tt.ffExists, tt.ffEnabled) + assert.Equal(t, tt.expectedLoggingBinDir, loggingBinDir) + }) + } +} + +func Test_defaultFluentBitExePath(t *testing.T) { + agentDir := "C:\\some\\agent\\dir" + integrationsDir := "integrations_dir" + + testCases := []struct { + name string + ffEnabled bool + ffExists bool + expectedExePath string + }{ + { + name: "no ff", + ffExists: false, + ffEnabled: false, + expectedExePath: "C:\\some\\agent\\dir\\integrations_dir\\logging\\fluent-bit.exe", + }, + { + name: "no ff but enabled", + ffExists: false, + ffEnabled: true, + expectedExePath: "C:\\some\\agent\\dir\\integrations_dir\\logging\\fluent-bit.exe", + }, + { + name: "disabled ff", + ffExists: true, + ffEnabled: false, + expectedExePath: "C:\\some\\agent\\dir\\integrations_dir\\logging\\fluent-bit.exe", + }, + { + name: "enabled ff", + ffExists: true, + ffEnabled: true, + expectedExePath: "C:\\some\\agent\\dir\\integrations_dir\\logging\\fluent-bit.exe", + }, + } + + cfg := fBSupervisorConfig{ + agentDir: agentDir, + integrationsDir: integrationsDir, + } + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + loggingBinDir := cfg.defaultLoggingBinDir(tt.ffExists, tt.ffEnabled) + exePath := cfg.defaultFluentBitExePath(tt.ffExists, tt.ffEnabled, loggingBinDir) + assert.Equal(t, tt.expectedExePath, exePath) + }) + } +} diff --git a/pkg/integrations/v4/supervisor_fb_test.go b/pkg/integrations/v4/supervisor_fb_test.go index a6c3f5cb6..2cd117d6c 100644 --- a/pkg/integrations/v4/supervisor_fb_test.go +++ b/pkg/integrations/v4/supervisor_fb_test.go @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package v4 +//nolint:gci import ( "crypto/rand" "fmt" @@ -11,13 +12,17 @@ import ( "os" "path" "path/filepath" + "runtime" "testing" - executor2 "github.com/newrelic/infrastructure-agent/internal/integrations/v4/executor" + "github.com/newrelic/infrastructure-agent/internal/agent/cmdchannel/fflag" + "github.com/newrelic/infrastructure-agent/internal/feature_flags" + "github.com/newrelic/infrastructure-agent/internal/integrations/v4/executor" "github.com/newrelic/infrastructure-agent/internal/testhelpers" "github.com/newrelic/infrastructure-agent/pkg/config" "github.com/newrelic/infrastructure-agent/pkg/entity" "github.com/newrelic/infrastructure-agent/pkg/integrations/v4/logs" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -34,13 +39,13 @@ func TestFBSupervisorConfig_IsLogForwarderAvailable(t *testing.T) { // GIVEN / THEN tests := []struct { name string - cfg FBSupervisorConfig + cfg fBSupervisorConfig want bool }{ { "incorrect: all non-existing", - FBSupervisorConfig{ - FluentBitExePath: nonExisting, + fBSupervisorConfig{ + fluentBitExePath: nonExisting, FluentBitNRLibPath: nonExisting, FluentBitParsersPath: nonExisting, ConfTemporaryFolder: os.TempDir(), @@ -49,8 +54,8 @@ func TestFBSupervisorConfig_IsLogForwarderAvailable(t *testing.T) { }, { "incorrect: NR lib and parsers do not exist", - FBSupervisorConfig{ - FluentBitExePath: existing, + fBSupervisorConfig{ + fluentBitExePath: existing, FluentBitNRLibPath: nonExisting, FluentBitParsersPath: nonExisting, ConfTemporaryFolder: os.TempDir(), @@ -59,8 +64,8 @@ func TestFBSupervisorConfig_IsLogForwarderAvailable(t *testing.T) { }, { "incorrect: parsers doesn't exist", - FBSupervisorConfig{ - FluentBitExePath: existing, + fBSupervisorConfig{ + fluentBitExePath: existing, FluentBitNRLibPath: existing, FluentBitParsersPath: nonExisting, ConfTemporaryFolder: os.TempDir(), @@ -69,8 +74,8 @@ func TestFBSupervisorConfig_IsLogForwarderAvailable(t *testing.T) { }, { "correct configuration", - FBSupervisorConfig{ - FluentBitExePath: existing, + fBSupervisorConfig{ + fluentBitExePath: existing, FluentBitNRLibPath: existing, FluentBitParsersPath: existing, ConfTemporaryFolder: os.TempDir(), @@ -98,7 +103,9 @@ func TestFBSupervisorConfig_IsLogForwarderAvailable(t *testing.T) { func TestFBSupervisorConfig_LicenseKeyShouldBePassedAsEnvVar(t *testing.T) { t.Parallel() - fbConf := FBSupervisorConfig{ConfTemporaryFolder: os.TempDir()} + fbConf := fBSupervisorConfig{ConfTemporaryFolder: os.TempDir()} + bypassIsLogForwarderAvailable(t, &fbConf) + agentIdentity := func() entity.Identity { return entity.Identity{ID: 13} } @@ -112,8 +119,8 @@ func TestFBSupervisorConfig_LicenseKeyShouldBePassedAsEnvVar(t *testing.T) { exec, err := executorBuilder() require.NoError(t, err) - assert.Contains(t, exec.(*executor2.Executor).Cfg.Environment, "NR_LICENSE_KEY_ENV_VAR") // nolint:forcetypeassert - assert.Equal(t, exec.(*executor2.Executor).Cfg.Environment["NR_LICENSE_KEY_ENV_VAR"], license) //nolint:forcetypeassert + assert.Contains(t, exec.(*executor.Executor).Cfg.Environment, "NR_LICENSE_KEY_ENV_VAR") // nolint:forcetypeassert + assert.Equal(t, exec.(*executor.Executor).Cfg.Environment["NR_LICENSE_KEY_ENV_VAR"], license) //nolint:forcetypeassert } func Test_ConfigTemporaryFolderCreation(t *testing.T) { @@ -127,7 +134,9 @@ func Test_ConfigTemporaryFolderCreation(t *testing.T) { os.Remove(termporaryFolderPath) }() - fbConf := FBSupervisorConfig{ConfTemporaryFolder: termporaryFolderPath} + fbConf := fBSupervisorConfig{ConfTemporaryFolder: termporaryFolderPath} + bypassIsLogForwarderAvailable(t, &fbConf) + agentIdentity := func() entity.Identity { return entity.Identity{ID: 13} } @@ -240,3 +249,222 @@ func addFile(t *testing.T, dir, name, contents string) { filePath := filepath.Join(dir, name) require.NoError(t, os.WriteFile(filePath, []byte(contents), 0o0600)) } + +//nolint:funlen +func TestNewSupervisorConfig(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + ffEnabled bool + ffExists bool + agentDir string + integrationsDir string + loggingBinDir string + fluentBitExePath string + fluentBitNRLibPath string + fluentBitParsersPath string + fbVerbose bool + expectedPathLinux string + expectedPathWindows string + }{ + { + name: "configuration should rule with no ff", + fluentBitExePath: "fluentBitExePath", + expectedPathLinux: "fluentBitExePath", + expectedPathWindows: "fluentBitExePath", + }, + { + name: "configuration should rule with no ff and loggin dir defined", + loggingBinDir: "loggingBinDir", + fluentBitExePath: "fluentBitExePath", + expectedPathLinux: "fluentBitExePath", + expectedPathWindows: "fluentBitExePath", + }, + { + name: "configuration should rule with ff disabled and loggin dir defined", + ffExists: true, + loggingBinDir: "loggingBinDir", + fluentBitExePath: "fluentBitExePath", + expectedPathLinux: "fluentBitExePath", + expectedPathWindows: "fluentBitExePath", + }, + { + name: "configuration should rule with ff enabled and loggin dir defined", + ffExists: true, + ffEnabled: true, + loggingBinDir: "loggingBinDir", + fluentBitExePath: "fluentBitExePath", + expectedPathLinux: "fluentBitExePath", + expectedPathWindows: "fluentBitExePath", + }, + { + name: "loggingBinDir configuration should rule when no fluentBitExePath is present", + loggingBinDir: "loggingBinDir", + integrationsDir: "integrationsDir", + expectedPathLinux: filepath.Join("loggingBinDir", "fluent-bit"), + expectedPathWindows: filepath.Join("loggingBinDir", "fluent-bit.exe"), + }, + { + name: "loggingBinDir configuration should rule when no fluentBitExePath is present with ff", + loggingBinDir: "loggingBinDir", + integrationsDir: "integrationsDir", + ffEnabled: true, + ffExists: true, + expectedPathLinux: filepath.Join("loggingBinDir", "td-agent-bit"), + expectedPathWindows: filepath.Join("loggingBinDir", "fluent-bit.exe"), + }, + { + name: "no conf options without ff", + integrationsDir: "integrationsDir", + agentDir: "some_agent_dir", + expectedPathLinux: filepath.Join("/opt/fluent-bit/bin", "fluent-bit"), + expectedPathWindows: filepath.Join("some_agent_dir", "integrationsDir", "logging", "fluent-bit.exe"), + }, + { + name: "no conf options with ff", + ffEnabled: true, + ffExists: true, + integrationsDir: "integrationsDir", + agentDir: "some_agent_dir", + expectedPathLinux: filepath.Join("/opt/td-agent-bit/bin", "td-agent-bit"), + expectedPathWindows: filepath.Join("some_agent_dir", "integrationsDir", "logging", "fluent-bit.exe"), + }, + } + + // create temp directory and set it as default directory to use for temporary files + tmpDir := t.TempDir() + + for i := range testCases { + testCase := testCases[i] + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + ffRetriever := &feature_flags.FeatureFlagRetrieverMock{} + ffRetriever.ShouldGetFeatureFlag(fflag.FlagFluentBit19, testCase.ffEnabled, testCase.ffExists) + + fbIntCfg := NewFBSupervisorConfig( + ffRetriever, + testCase.agentDir, + testCase.integrationsDir, + testCase.loggingBinDir, + testCase.fluentBitExePath, + testCase.fluentBitNRLibPath, + testCase.fluentBitParsersPath, + testCase.fbVerbose, + tmpDir, + ) + + path := fbIntCfg.getFbPath() + if runtime.GOOS == "linux" { + assert.Equal(t, testCase.expectedPathLinux, path) + } + if runtime.GOOS == "windows" { + assert.Equal(t, testCase.expectedPathWindows, path) + } + }) + } +} + +func Test_buildFbExecutorFailsIfNoFbFiles(t *testing.T) { + t.Parallel() + + ffRetriever := &feature_flags.FeatureFlagRetrieverMock{} + ffRetriever.ShouldNotGetFeatureFlag(fflag.FlagFluentBit19) + + //nolint:goconst + agentDir := "agentDir" + integrationsDir := "integrationsDir" + loggingBinDir := "loggingBinDir" + fbVerbose := false + // create temp directory and set it as default directory to use for temporary files + tmpDir := t.TempDir() + + fbIntCfg := NewFBSupervisorConfig( + ffRetriever, + agentDir, + integrationsDir, + loggingBinDir, + "not existent file", + "not existent file", + "not existent file", + fbVerbose, + tmpDir, + ) + + executorBuilder := buildFbExecutor(fbIntCfg, confLoaderForTest()) + _, err := executorBuilder() + require.ErrorIs(t, err, errFbNotAvailable) +} + +func Test_buildFbExecutor(t *testing.T) { + t.Parallel() + + tmpDir, err := os.MkdirTemp("", "") + assert.NoError(t, err) + + defer func() { + os.RemoveAll(tmpDir) + }() + + fluentBitExePath, err := os.CreateTemp(tmpDir, "fb_exe_") + assert.NoError(t, err) + fluentBitNRLibPath, err := os.CreateTemp(tmpDir, "fb_lib") + assert.NoError(t, err) + fluentBitParsersPath, err := os.CreateTemp(tmpDir, "fb_parser") + assert.NoError(t, err) + + ffRetriever := &feature_flags.FeatureFlagRetrieverMock{} + ffRetriever.ShouldNotGetFeatureFlag(fflag.FlagFluentBit19) + + agentDir := "agentDir" + integrationsDir := "agentDir" + loggingBinDir := "loggingBinDir" + fbVerbose := false + // create temp directory and set it as default directory to use for temporary files + fbTmpDir, err := os.MkdirTemp(tmpDir, "fb_tmp_dir") + assert.NoError(t, err) + + fbIntCfg := NewFBSupervisorConfig( + ffRetriever, + agentDir, + integrationsDir, + loggingBinDir, + fluentBitExePath.Name(), + fluentBitNRLibPath.Name(), + fluentBitParsersPath.Name(), + fbVerbose, + fbTmpDir, + ) + + executorBuilder := buildFbExecutor(fbIntCfg, confLoaderForTest()) + + exec, err := executorBuilder() + require.NoError(t, err) + + assert.Equal(t, fbIntCfg.getFbPath(), exec.(*executor.Executor).Command) //nolint:forcetypeassert + assert.Equal(t, fluentBitNRLibPath.Name(), exec.(*executor.Executor).Args[3]) //nolint:forcetypeassert + assert.Equal(t, fluentBitParsersPath.Name(), exec.(*executor.Executor).Args[5]) //nolint:forcetypeassert +} + +func confLoaderForTest() *logs.CfgLoader { + agentIdentity := func() entity.Identity { + return entity.Identity{ID: 13} + } + hostnameResolver := testhelpers.NewFakeHostnameResolver("full_hostname", "short_hostname", nil) + license := "some_license" + c := config.LogForward{License: license, Troubleshoot: config.Troubleshoot{Enabled: true}} + + return logs.NewFolderLoader(c, agentIdentity, hostnameResolver) +} + +// bypassIsLogForwarderAvailable bypasses the check of some files to be able to run fb +// this check was not done before the FF so in some tests this needs to be bypassed. +func bypassIsLogForwarderAvailable(t *testing.T, conf *fBSupervisorConfig) { + t.Helper() + // bypass is forwarder available + file, err := os.CreateTemp("", "") + assert.NoError(t, err) + conf.fluentBitExePath = file.Name() + conf.FluentBitNRLibPath = file.Name() + conf.FluentBitParsersPath = file.Name() +} diff --git a/pkg/integrations/v4/supervisor_test.go b/pkg/integrations/v4/supervisor_test.go index 503718a39..dc80dd751 100644 --- a/pkg/integrations/v4/supervisor_test.go +++ b/pkg/integrations/v4/supervisor_test.go @@ -203,6 +203,7 @@ func NewSupervisorFromMock(supervisorMock *SupervisorMock) *Supervisor { getBackOffTimer: supervisorMock.getBackOffTimer, parseOutputFn: logs.ParseFBOutput, hostnameChangeNotifier: supervisorMock.hostnameNotifier, + restartCh: make(chan struct{}, 1), } } @@ -239,7 +240,6 @@ func (sm *SupervisorMock) getBackOffTimer(duration time.Duration) *time.Timer { } func TestSupervisor_RestartOnHostnameChange(t *testing.T) { - notifierMock := NewNotifierMock() supervisorMock := NewSupervisorMock(notifierMock) diff --git a/test/packaging/ansible/installation-windows.yml b/test/packaging/ansible/installation-windows.yml index 71f1ee265..6a53cab81 100644 --- a/test/packaging/ansible/installation-windows.yml +++ b/test/packaging/ansible/installation-windows.yml @@ -1,8 +1,14 @@ --- -- hosts: testing_hosts_windows +- name: installation-windows + hosts: testing_hosts_windows gather_facts: yes + pre_tasks: + - name: Initial cleanup # Only required for shared infra. + include_role: + name: cleanup + tasks: - name: Installation tests suite @@ -16,4 +22,12 @@ include_role: name: agent-install + - name: Assert version + include_role: + name: assert-version + + always: + - name: Final cleanup # Only required for shared infra. + include_role: + name: cleanup ... \ No newline at end of file diff --git a/test/packaging/ansible/log-forwarder.yml b/test/packaging/ansible/log-forwarder.yml index a5cedf39d..4bea8de30 100644 --- a/test/packaging/ansible/log-forwarder.yml +++ b/test/packaging/ansible/log-forwarder.yml @@ -122,4 +122,55 @@ include_role: name: cleanup + +- name: log-forwarder-windows + hosts: windows_amd64 + gather_facts: yes + + pre_tasks: + - name: Initial cleanup # Only required for shared infra. + include_role: + name: cleanup + + tasks: + - name: Log forwarder tests suite + vars: + env_vars: + + block: + + - name: Define variable with supported versions + set_fact: + log_forwader_supported: true + when: inventory_hostname is search("windows") + + - name: repo setup + include_role: + name: repo-setup + when: log_forwader_supported is defined + + - name: setup config + include_role: + name: setup-config + vars: + log_level: 'debug' + log_forward: 'true' + when: log_forwader_supported is defined + + - name: install agent + include_role: + name: agent-install + when: log_forwader_supported is defined + + # Not available for ARM yet + - name: Log forwarder + include_role: + name: logging + when: log_forwader_supported is defined + + always: + - name: Final cleanup # Only required for shared infra. + include_role: + name: cleanup + ... diff --git a/test/packaging/ansible/roles/assert-version/tasks/assert-version-Win32NT.yaml b/test/packaging/ansible/roles/assert-version/tasks/assert-version-Win32NT.yaml new file mode 100644 index 000000000..770affa4f --- /dev/null +++ b/test/packaging/ansible/roles/assert-version/tasks/assert-version-Win32NT.yaml @@ -0,0 +1,12 @@ +--- + +- name: Assert expected version + ansible.windows.win_command: '"C:\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" "--version"' + register: check + +- name: Stdout from version grep + fail: + msg: "{{ check.stdout | regex_search('New Relic Infrastructure Agent version: ([^,]+)', '\\1') | first }} does not match {{ target_agent_version }}" + when: "{{ check.stdout | regex_search('New Relic Infrastructure Agent version: ([^,]+)', '\\1') | first != target_agent_version }}" + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/cleanup/tasks/files-Win32NT.yaml b/test/packaging/ansible/roles/cleanup/tasks/files-Win32NT.yaml new file mode 100644 index 000000000..435d1db79 --- /dev/null +++ b/test/packaging/ansible/roles/cleanup/tasks/files-Win32NT.yaml @@ -0,0 +1,10 @@ +--- + +- name: remove infra-agent files and directories + ansible.windows.win_file: + path: "{{ item }}" + state: absent + loop: + - 'C:\Program Files\New Relic\newrelic-infra' + +... diff --git a/test/packaging/ansible/roles/cleanup/tasks/package-Windows.yaml b/test/packaging/ansible/roles/cleanup/tasks/package-Windows.yaml new file mode 100644 index 000000000..8486482ec --- /dev/null +++ b/test/packaging/ansible/roles/cleanup/tasks/package-Windows.yaml @@ -0,0 +1,14 @@ +--- + +- name: Get infra agent productID + ansible.windows.win_powershell: + script: (Get-WmiObject win32_product | where{$_.name -eq "New Relic Infrastructure Agent"}).IdentifyingNumber + register: infra_agent_info + +- name: Uninstall infra agent + win_package: + product_id: "{{ infra_agent_info.output[0] }}" + state: absent + when: infra_agent_info.output[0] != None + +... diff --git a/test/packaging/ansible/roles/cleanup/tasks/service-Win32NT.yaml b/test/packaging/ansible/roles/cleanup/tasks/service-Win32NT.yaml new file mode 100644 index 000000000..3b576e250 --- /dev/null +++ b/test/packaging/ansible/roles/cleanup/tasks/service-Win32NT.yaml @@ -0,0 +1,10 @@ +--- + +- name: stop newrelic-infra service + win_service: + name: New Relic Infrastructure Agent + state: stopped + ignore_errors: true + failed_when: false + +... diff --git a/test/packaging/ansible/roles/logging/tasks/main.yaml b/test/packaging/ansible/roles/logging/tasks/main.yaml index 4d7864d6b..ba1e6ff56 100644 --- a/test/packaging/ansible/roles/logging/tasks/main.yaml +++ b/test/packaging/ansible/roles/logging/tasks/main.yaml @@ -1,50 +1,14 @@ --- -- name: Test with retry if Fluent-Bit process started - command: pgrep -f td-agent-bit.*newrelic - register: output1 - changed_when: false - until: output1.rc == 0 - retries: 3 - delay: 5 +- name: Assert that multiple versions (td-agent-bit and fluent-bit) are installed in linux + include_tasks: "multiple_version_assertion_{{ ansible_os_family }}.yaml" + when: ansible_system == "Linux" -- name: Wait for 5 seconds before checking Fluent-Bit PID again - pause: - seconds: 5 +- name: Assert that multiple versions (td-agent-bit and fluent-bit) are installed in windows + include_tasks: "multiple_version_assertion_{{ ansible_system }}.yaml" + when: ansible_system == "Win32NT" -- name: Test Fluent-Bit still running - command: pgrep -f td-agent-bit.*newrelic - register: output2 - changed_when: false - -- name: Test Fluent-Bit has the same PID (process didn't died) - fail: - msg: | - Fluent-Bit changed pid: - from: {{ output1.stdout }} - to: {{ output2.stdout }} - when: output1.stdout != output2.stdout - -- name: Get Fluent-Bit version - command: "/opt/td-agent-bit/bin/td-agent-bit -V" - register: version - ignore_errors: true - -- name: Test Fluent-Bit has the correct version - fail: - msg: | - Fluent-Bit Version ouput: "{{ version.stdout }}", does't contain expected version: "{{ expected_fb_version }}" - when: 'expected_fb_version not in version.stdout' - -- name: Get Fluent-Bit build arch - command: "file /opt/td-agent-bit/bin/td-agent-bit" - register: arch - ignore_errors: true - -- name: Test Fluent-Bit has the correct arch - fail: - msg: | - Fluent-Bit ouput: "{{ arch.stdout }}", does't contain expected version: "{{ expected_fb_arch }}" - when: 'expected_fb_arch not in arch.stdout' +- name: Assert process is running + include_tasks: "process_running_{{ ansible_system }}.yaml" ... diff --git a/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Debian.yaml b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Debian.yaml new file mode 100644 index 000000000..f2f4fe4e9 --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Debian.yaml @@ -0,0 +1,7 @@ +--- + +- name: assert tf-agent-bit and fluent-bit are installed + shell: dpkg -l | grep {{ item }} + loop: "{{ packages_linux }}" + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_RedHat.yaml b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_RedHat.yaml new file mode 100644 index 000000000..2566ec71e --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_RedHat.yaml @@ -0,0 +1,7 @@ +--- + +- name: assert tf-agent-bit and fluent-bit are installed + shell: rpm -qav | grep {{ item }} + loop: "{{ packages_linux }}" + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Suse.yaml b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Suse.yaml new file mode 100644 index 000000000..aa8dd8260 --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Suse.yaml @@ -0,0 +1,5 @@ +--- + +- include_tasks: multiple_version_assertion_RedHat.yaml + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Win32NT.yaml b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Win32NT.yaml new file mode 100644 index 000000000..083ecc868 --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/multiple_version_assertion_Win32NT.yaml @@ -0,0 +1,15 @@ +--- + +- name: register windows binaries info + win_stat: + path: "{{ item }}" + register: windows_binaries_info + loop: "{{ windows_binaries_paths }}" + +- name: assert windows binaries exists + fail: + msg: windows binary does not exist + when: not item.stat.exists + loop: "{{ windows_binaries_info.results }}" + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/tasks/process_running_Linux.yaml b/test/packaging/ansible/roles/logging/tasks/process_running_Linux.yaml new file mode 100644 index 000000000..3aeb7d211 --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/process_running_Linux.yaml @@ -0,0 +1,50 @@ +--- + +- name: Test with retry if Fluent-Bit process started + command: pgrep -f fluent-bit.*newrelic + register: output1 + changed_when: false + until: output1.rc == 0 + retries: 3 + delay: 5 + +- name: Wait for 5 seconds before checking Fluent-Bit PID again + pause: + seconds: 5 + +- name: Test Fluent-Bit still running + command: pgrep -f fluent-bit.*newrelic + register: output2 + changed_when: false + +- name: Test Fluent-Bit has the same PID (process didn't died) + fail: + msg: | + Fluent-Bit changed pid: + from: {{ output1.stdout }} + to: {{ output2.stdout }} + when: output1.stdout != output2.stdout + +- name: Get Fluent-Bit version + command: "/opt/fluent-bit/bin/fluent-bit -V" + register: version + ignore_errors: true + +- name: Test Fluent-Bit has the correct version + fail: + msg: | + Fluent-Bit Version ouput: "{{ version.stdout }}", does't contain expected version: "{{ expected_fb_version }}" + when: 'expected_fb_version not in version.stdout' + +- name: Get Fluent-Bit build arch + command: "file /opt/fluent-bit/bin/fluent-bit" + register: arch + ignore_errors: true + +- name: Test Fluent-Bit has the correct arch + fail: + msg: | + Fluent-Bit ouput: "{{ arch.stdout }}", does't contain expected version: "{{ expected_fb_arch }}" + when: 'expected_fb_arch not in arch.stdout' + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/tasks/process_running_Win32NT.yaml b/test/packaging/ansible/roles/logging/tasks/process_running_Win32NT.yaml new file mode 100644 index 000000000..6f173763e --- /dev/null +++ b/test/packaging/ansible/roles/logging/tasks/process_running_Win32NT.yaml @@ -0,0 +1,15 @@ +--- + +- name: Ensure fluent-bit is running + win_shell: "ps | ? { $_.name -eq 'fluent-bit' } | ft path -auto" + register: running_processes + become: yes + become_user: Administrator + become_method: runas + +- name: Fail if fluent-bit is not running from the specified path + fail: + msg: "fluent-bit is not running from the specified path" + when: running_processes.stdout is not search(fluent_bit_full_path_regex) + +... \ No newline at end of file diff --git a/test/packaging/ansible/roles/logging/vars/main.yaml b/test/packaging/ansible/roles/logging/vars/main.yaml index e6af3d2b6..85799c290 100644 --- a/test/packaging/ansible/roles/logging/vars/main.yaml +++ b/test/packaging/ansible/roles/logging/vars/main.yaml @@ -3,4 +3,12 @@ expected_fb_version: "{{ lookup('env', 'FLUENT_BIT_VERSION') }}" expected_fb_arch: "{{ lookup('env', 'FLUENT_BIT_ARCH') }}" +packages_linux: + - td-agent-bit + - fluent-bit + +windows_binaries_paths: + - "C:\\Program Files\\New Relic\\newrelic-infra\\newrelic-integrations\\logging\\fluent-bit.exe" + +fluent_bit_full_path_regex: 'C:\\Program Files\\New Relic\\newrelic-infra\\newrelic-integrations\\logging\\fluent-bit\.exe' ... diff --git a/test/packaging/ansible/roles/package-uninstall/tasks/package-Windows.yaml b/test/packaging/ansible/roles/package-uninstall/tasks/package-Windows.yaml new file mode 100644 index 000000000..8486482ec --- /dev/null +++ b/test/packaging/ansible/roles/package-uninstall/tasks/package-Windows.yaml @@ -0,0 +1,14 @@ +--- + +- name: Get infra agent productID + ansible.windows.win_powershell: + script: (Get-WmiObject win32_product | where{$_.name -eq "New Relic Infrastructure Agent"}).IdentifyingNumber + register: infra_agent_info + +- name: Uninstall infra agent + win_package: + product_id: "{{ infra_agent_info.output[0] }}" + state: absent + when: infra_agent_info.output[0] != None + +... diff --git a/test/packaging/ansible/test.yml b/test/packaging/ansible/test.yml index 5ab9947d4..e5452fc35 100644 --- a/test/packaging/ansible/test.yml +++ b/test/packaging/ansible/test.yml @@ -15,6 +15,9 @@ - name: agent installation via newrelic-cli import_playbook: installation-newrelic-cli.yml +- name: installation windows + import_playbook: installation-windows.yml + - name: log forwarder import_playbook: log-forwarder.yml