From 95ffc90043fd44b3db5b4f28afae1c1c00de8314 Mon Sep 17 00:00:00 2001 From: Philip White Date: Sun, 1 Sep 2024 00:14:02 -0700 Subject: [PATCH] amazon-cloudwatch-agent: init at 1.300044.0 **Amazon CloudWatch Agent** is an agent that collects data about the running server and sends metrics and logs to the *Amazon CloudWatch* service. This commit also introduces a corresponding NixOS service module to manage the Amazon CloudWatch Agent via systemd. Based on https://github.com/wearetechnative/amazon-cloudwatch-agent-nix/blob/main/module.nix --- .../manual/release-notes/rl-2411.section.md | 2 + .../monitoring/amazon-cloudwatch-agent.nix | 147 ++++++++++++++++++ .../am/amazon-cloudwatch-agent/package.nix | 83 ++++++++++ 3 files changed, 232 insertions(+) create mode 100644 nixos/modules/services/monitoring/amazon-cloudwatch-agent.nix create mode 100644 pkgs/by-name/am/amazon-cloudwatch-agent/package.nix diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 4f773fccd23a14e..6912160372fa82a 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -126,6 +126,8 @@ - [ToDesk](https://www.todesk.com/linux.html), a remote desktop applicaton. Available as [services.todesk.enable](#opt-services.todesk.enable). +- [Amazon CloudWatch Agent](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-commandline-fleet.html#install-CloudWatch-Agent-iam_user-first), an agent for collecting metrics and logs and sending them to *Amazon CloudWatch*. + ## Backward Incompatibilities {#sec-release-24.11-incompatibilities} - `transmission` package has been aliased with a `trace` warning to `transmission_3`. Since [Transmission 4 has been released last year](https://github.com/transmission/transmission/releases/tag/4.0.0), and Transmission 3 will eventually go away, it was decided perform this warning alias to make people aware of the new version. The `services.transmission.package` defaults to `transmission_3` as well because the upgrade can cause data loss in certain specific usage patterns (examples: [#5153](https://github.com/transmission/transmission/issues/5153), [#6796](https://github.com/transmission/transmission/issues/6796)). Please make sure to back up to your data directory per your usage: diff --git a/nixos/modules/services/monitoring/amazon-cloudwatch-agent.nix b/nixos/modules/services/monitoring/amazon-cloudwatch-agent.nix new file mode 100644 index 000000000000000..417c42faad43d2c --- /dev/null +++ b/nixos/modules/services/monitoring/amazon-cloudwatch-agent.nix @@ -0,0 +1,147 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + inherit (lib) + attrsets + mkEnableOption + mkOption + optionalAttrs + types + ; + + cfg = config.services.amazon-cloudwatch-agent; + + assembledConfig = attrsets.mergeAttrsList [ + (optionalAttrs (cfg.configAgent != null) { agent = cfg.configAgent; }) + (optionalAttrs (cfg.configMetrics != null) { metrics = cfg.configMetrics; }) + (optionalAttrs (cfg.configLogs != null) { logs = cfg.configLogs; }) + (optionalAttrs (cfg.configTraces != null) { traces = cfg.configTraces; }) + ]; + + agentConfigFile = (pkgs.formats.json { }).generate "config.json" assembledConfig; + + awsCredsFile = (pkgs.formats.ini { }).generate "aws-credentials" { + AmazonCloudWatchAgent = cfg.configAwsCreds; + }; + + commonConfigTomlFile = (pkgs.formats.toml { }).generate "common-config.toml" { + credentials = { + shared_credential_file = "${awsCredsFile}"; + shared_credential_profile = "AmazonCloudWatchAgent"; + }; + }; +in +{ + options = { + services.amazon-cloudwatch-agent = { + package = lib.mkPackageOption pkgs "amazon-cloudwatch-agent" { }; + + enable = mkEnableOption '' + Amazon CloudWatch Amazon + ''; + + configAwsCreds = mkOption { + type = types.submodule { + freeformType = with types; attrsOf str; + }; + description = "AWS credentials for CloudWatch Agent (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-premise.html)"; + default = { + aws_access_key_id = "FILL-IN"; + aws_secret_access_key = "FILL-IN"; + region = "FILL-IN"; + }; + }; + + configAgent = mkOption { + type = types.submodule { + freeformType = types.oneOf [ + (pkgs.formats.json { }).type + null + ]; + }; + description = "Agent section of the CloudWatch Agent configuration (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html)"; + default = null; + }; + + configMetrics = mkOption { + type = types.submodule { + freeformType = types.oneOf [ + (pkgs.formats.json { }).type + null + ]; + }; + description = "Metrics section of the CloudWatch Agent configuration (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html)"; + default = null; + }; + + configLogs = mkOption { + type = types.nullOr ( + types.submodule { + freeformType = (pkgs.formats.json { }).type; + } + ); + description = "Logs section of the CloudWatch Agent configuration (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html)"; + default = null; # not empty object because, if we specify the key, we must also specify certain child attributes. + }; + + configTraces = mkOption { + type = types.nullOr ( + types.submodule { + freeformType = (pkgs.formats.json { }).type; + } + ); + description = "Traces section of the CloudWatch Agent configuration (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html)"; + default = null; # not empty object because, if we specify the key, we must also specify certain child attributes. + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; # FIXME: what does this do? + + users.users.cwagent = { + description = "amazon-cloudwatch-agent daemon user"; + isSystemUser = true; + group = "cwagent"; + }; + + users.groups.cwagent = { }; + + systemd.tmpfiles.rules = [ + "D /opt/aws/amazon-cloudwatch-agent/etc 750 cwagent cwagent" # for symlinks made by this file, and where the agent wants to write the toml config + "D /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d 750 cwagent cwagent" # where the agent wants to write to + "D /opt/aws/amazon-cloudwatch-agent/logs 750 cwagent cwagent" + "D /opt/aws/amazon-cloudwatch-agent/var 750 cwagent cwagent" + "L+ /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml - - - - ${commonConfigTomlFile}" + "L+ /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json - - - - ${agentConfigFile}" + "L+ /opt/aws/amazon-cloudwatch-agent/bin - - - - ${cfg.package}/bin" + ]; + + systemd.services.amazon-cloudwatch-agent = { + enable = true; + description = "Amazon CloudWatch Agent"; + documentation = [ + "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html" + ]; + + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + # systemd runs the agent as root, then the agent will switch to the dedicated user + Type = "simple"; + Restart = "on-failure"; + RestartSec = 60; + ExecStart = "${cfg.package}/bin/start-amazon-cloudwatch-agent"; + KillMode = "process"; + # According to systemd documentation, the simple type does not need this, but we have it anyway, so can't hurt to specify it. + PIDFile = "/opt/aws/amazon-cloudwatch-agent/var/amazon-cloudwatch-agent.pid"; + }; + }; + }; +} diff --git a/pkgs/by-name/am/amazon-cloudwatch-agent/package.nix b/pkgs/by-name/am/amazon-cloudwatch-agent/package.nix new file mode 100644 index 000000000000000..5ee5585027152e7 --- /dev/null +++ b/pkgs/by-name/am/amazon-cloudwatch-agent/package.nix @@ -0,0 +1,83 @@ +{ + config, + lib, + buildGoModule, + fetchgit, + pkgs, +}: + +buildGoModule rec { + pname = "amazon-cloudwatch-agent"; + version = "1.300044.0"; + + src = fetchgit { + url = "https://github.com/aws/amazon-cloudwatch-agent.git"; + rev = "v${version}"; + sha256 = "sha256-sG0dvmTagpob23/5L2QB32bwFmmRygEQKrAmgAWgEOE="; + }; + + vendorHash = "sha256-a1xjnVXvSinYGqjFOmlCxJwWc9sc9OAfSuAMRCAlxCM="; + + meta = with lib; { + description = "Amazon CloudWatch Agent"; + homepage = "https://github.com/aws/amazon-cloudwatch-agent"; + license = licenses.mit; + maintainers = with lib.maintainers; [ pmw ]; + # The agent supports MacOS and Windows, but it's not currently working for me on macOS: + # > cannot execute binary file: Exec format error + # so I am declaring support only for Linux where I tested it personally. + platforms = with lib.platforms; linux; + }; + + doCheck = false; + + patchPhase = '' + + echo "" >> Makefile + echo "amazon-cloudwatch-agent-nixos-linux: copy-version-file" >> Makefile + echo -e "\t@echo Building CloudWatchAgent for Linux,Debian with ARM64 and AMD64" >> Makefile + echo -e "\t\$(LINUX_AMD64_BUILD)/config-downloader github.com/aws/amazon-cloudwatch-agent/cmd/config-downloader" >> Makefile + echo -e "\t\$(LINUX_AMD64_BUILD)/config-translator github.com/aws/amazon-cloudwatch-agent/cmd/config-translator" >> Makefile + echo -e "\t\$(LINUX_AMD64_BUILD)/amazon-cloudwatch-agent github.com/aws/amazon-cloudwatch-agent/cmd/amazon-cloudwatch-agent" >> Makefile + echo -e "\t\$(LINUX_AMD64_BUILD)/start-amazon-cloudwatch-agent github.com/aws/amazon-cloudwatch-agent/cmd/start-amazon-cloudwatch-agent" >> Makefile + echo -e "\t\$(LINUX_AMD64_BUILD)/amazon-cloudwatch-agent-config-wizard github.com/aws/amazon-cloudwatch-agent/cmd/amazon-cloudwatch-agent-config-wizard" >> Makefile + + ''; + + buildPhase = '' + + export FAKEBUILD="false" + + if [ $FAKEBUILD == "true" ] + then + mkdir -p build/bin/linux_amd64 + touch build/bin/linux_amd64/fakebin + else + make amazon-cloudwatch-agent-nixos-linux + fi + + ''; + + installPhase = '' + + runHook preInstall + + mkdir -p $out/etc + + cp -av build/bin/linux_amd64 $out/bin + + cp LICENSE $out/ + cp NOTICE $out/ + cp licensing/THIRD-PARTY-LICENSES $out/ + cp RELEASE_NOTES $out/ + cp packaging/dependencies/amazon-cloudwatch-agent-ctl $out/bin/ + + # TODO in patchPhase + + mkdir -p /tmp/amazon-cloudwatch-agent + touch /tmp/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log + ln -s /tmp/amazon-cloudwatch-agent/log $out/log + + runHook postInstall + ''; +}