Skip to content

Commit

Permalink
amazon-cloudwatch-agent: init at 1.300048.1
Browse files Browse the repository at this point in the history
  • Loading branch information
commiterate committed Nov 9, 2024
1 parent 73e03e0 commit 37cd2b9
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 0 deletions.
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@

- [foot](https://codeberg.org/dnkl/foot), a fast, lightweight and minimalistic Wayland terminal emulator. Available as [programs.foot](#opt-programs.foot.enable).

- [Amazon CloudWatch Agent](https://github.com/aws/amazon-cloudwatch-agent), the official telemetry collector for AWS CloudWatch and AWS X-Ray. Available as [services.amazon-cloudwatch-agent](#opt-services.amazon-cloudwatch-agent.enable).

- [ToDesk](https://www.todesk.com/linux.html), a remote desktop application. Available as [services.todesk](#opt-services.todesk.enable).

- [Dependency Track](https://dependencytrack.org/), an intelligent Component Analysis platform that allows organizations to identify and reduce risk in the software supply chain. Available as [services.dependency-track](option.html#opt-services.dependency-track.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,7 @@
./services/misc/zookeeper.nix
./services/monitoring/alerta.nix
./services/monitoring/alloy.nix
./services/monitoring/amazon-cloudwatch-agent.nix
./services/monitoring/apcupsd.nix
./services/monitoring/arbtt.nix
./services/monitoring/below.nix
Expand Down
179 changes: 179 additions & 0 deletions nixos/modules/services/monitoring/amazon-cloudwatch-agent.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.amazon-cloudwatch-agent;

tomlFormat = pkgs.formats.toml { };
jsonFormat = pkgs.formats.json { };

commonConfigurationFile = tomlFormat.generate "common-config.toml" cfg.commonConfiguration;
configurationFile = jsonFormat.generate "amazon-cloudwatch-agent.json" cfg.configuration;
# See https://docs.aws.amazon.com/prescriptive-guidance/latest/implementing-logging-monitoring-cloudwatch/create-store-cloudwatch-configurations.html#store-cloudwatch-configuration-s3.
#
# We don't use the multiple JSON configuration files feature,
# but "config-translator" will log a benign error if the "-input-dir" option is omitted or is a non-existent directory.
#
# Create an empty directory to hide this benign error log. This prevents false-positives if users filter for "error" in the agent logs.
configurationDirectory = pkgs.runCommand "amazon-cloudwatch-agent.d" { } "mkdir $out";
in
{
options.services.amazon-cloudwatch-agent = {
enable = lib.mkEnableOption "Amazon CloudWatch Agent";
package = lib.mkPackageOption pkgs "amazon-cloudwatch-agent" { };
commonConfiguration = lib.mkOption {
type = tomlFormat.type;
default = { };
description = ''
Amazon CloudWatch Agent common configuration. See
<https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-commandline-fleet.html#CloudWatch-Agent-profile-instance-first>
for supported values.
'';
example = {
credentials = {
shared_credential_profile = "profile_name";
shared_credential_file = "/path/to/credentials";
};
proxy = {
http_proxy = "http_url";
https_proxy = "https_url";
no_proxy = "domain";
};
};
};
configuration = lib.mkOption {
type = jsonFormat.type;
default = { };
description = ''
Amazon CloudWatch Agent configuration. See
<https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html>
for supported values.
'';
# Subset of "CloudWatch agent configuration file: Complete examples" and "CloudWatch agent configuration file: Traces section" in the description link.
#
# Log file path changed from "/opt/aws/amazon-cloudwatch-agent/logs" to "/var/log/amazon-cloudwatch-agent" to follow the FHS.
example = {
agent = {
metrics_collection_interval = 10;
logfile = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
};
metrics = {
namespace = "MyCustomNamespace";
metrics_collected = {
cpu = {
resource = [ "*" ];
measurement = [
{
name = "cpu_usage_idle";
rename = "CPU_USAGE_IDLE";
unit = "Percent";
}
{
name = "cpu_usage_nice";
unit = "Percent";
}
"cpu_usage_guest"
];
totalcpu = false;
metrics_collection_interval = 10;
append_dimensions = {
customized_dimension_key_1 = "customized_dimension_value_1";
customized_dimension_key_2 = "customized_dimension_value_2";
};
};
};
};
logs = {
logs_collected = {
files = {
collect_list = [
{
file_path = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
log_group_name = "amazon-cloudwatch-agent.log";
log_stream_name = "{instance_id}";
timezone = "UTC";
}
];
};
};
log_stream_name = "log_stream_name";
force_flush_interval = 15;
};
traces = {
traces_collected = {
xray = { };
oltp = { };
};
};
};
};
mode = lib.mkOption {
type = lib.types.str;
default = "auto";
description = ''
Amazon CloudWatch Agent mode. Indicates whether the agent is running in EC2 ("ec2"), on-premises ("onPremise"),
or if it should guess based on metadata endpoints like IMDS or the ECS task metadata endpoint ("auto").
'';
example = "onPremise";
};
};

config = lib.mkIf cfg.enable {
# See https://github.com/aws/amazon-cloudwatch-agent/blob/v1.300048.1/packaging/dependencies/amazon-cloudwatch-agent.service.
systemd.services.amazon-cloudwatch-agent = {
description = "Amazon CloudWatch Agent";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
# "start-amazon-cloudwatch-agent" assumes the package is installed at "/opt/aws/amazon-cloudwatch-agent" so we can't use it.
#
# See https://github.com/aws/amazon-cloudwatch-agent/issues/1319.
#
# This program:
# 1. Switches to a non-root user if configured.
# 2. Runs "config-translator" to translate the input JSON configuration files into separate TOML (for CloudWatch Logs + Metrics),
# YAML (for X-Ray + OpenTelemetry), and JSON (for environment variables) configuration files.
# 3. Runs "amazon-cloudwatch-agent" with the paths to these generated files.
#
# Re-implementing with systemd options.
User = lib.attrByPath [
"agent"
"run_as_user"
] "root" cfg.configuration;
RuntimeDirectory = "amazon-cloudwatch-agent";
LogsDirectory = "amazon-cloudwatch-agent";
ExecStartPre = ''
${cfg.package}/bin/config-translator \
-config ${commonConfigurationFile} \
-input ${configurationFile} \
-input-dir ${configurationDirectory} \
-mode ${cfg.mode} \
-output ''${RUNTIME_DIRECTORY}/amazon-cloudwatch-agent.toml
'';
ExecStart = ''
${cfg.package}/bin/amazon-cloudwatch-agent \
-config ''${RUNTIME_DIRECTORY}/amazon-cloudwatch-agent.toml \
-envconfig ''${RUNTIME_DIRECTORY}/env-config.json \
-otelconfig ''${RUNTIME_DIRECTORY}/amazon-cloudwatch-agent.yaml \
-pidfile ''${RUNTIME_DIRECTORY}/amazon-cloudwatch-agent.pid
'';
KillMode = "process";
Restart = "on-failure";
RestartSec = 60;
};
restartTriggers = [
cfg.package
commonConfigurationFile
configurationFile
configurationDirectory
cfg.mode
];
};
};

meta.maintainers = pkgs.amazon-cloudwatch-agent.meta.maintainers;
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ in {
alloy = handleTest ./alloy.nix {};
allTerminfo = handleTest ./all-terminfo.nix {};
alps = handleTest ./alps.nix {};
amazon-cloudwatch-agent = handleTest ./amazon-cloudwatch-agent.nix {};
amazon-init-shell = handleTest ./amazon-init-shell.nix {};
amazon-ssm-agent = handleTest ./amazon-ssm-agent.nix {};
amd-sev = runTest ./amd-sev.nix;
Expand Down
93 changes: 93 additions & 0 deletions nixos/tests/amazon-cloudwatch-agent.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import ./make-test-python.nix (
{ lib, pkgs, ... }:
let
# See https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
iniFormat = pkgs.formats.ini { };

region = "ap-northeast-1";
sharedConfigurationDefaultProfile = "default";
sharedConfigurationFile = iniFormat.generate "config" {
"${sharedConfigurationDefaultProfile}" = {
region = region;
};
};
sharedCredentialsFile = iniFormat.generate "credentials" {
"${sharedConfigurationDefaultProfile}" = {
aws_access_key_id = "placeholder";
aws_secret_access_key = "placeholder";
aws_session_token = "placeholder";
};
};
sharedConfigurationDirectory = pkgs.runCommand ".aws" { } ''
mkdir $out
cp ${sharedConfigurationFile} $out/config
cp ${sharedCredentialsFile} $out/credentials
'';
in
{
name = "amazon-cloudwatch-agent";
meta.maintainers = pkgs.amazon-cloudwatch-agent.meta.maintainers;

nodes.machine =
{ config, pkgs, ... }:
{
services.amazon-cloudwatch-agent = {
enable = true;
commonConfiguration = {
credentials = {
shared_credential_profile = sharedConfigurationDefaultProfile;
shared_credential_file = "${sharedConfigurationDirectory}/credentials";
};
};
configuration = {
agent = {
# Required despite documentation saying the agent ignores it in "onPremise" mode.
region = region;

# Show debug logs and write to a file for interactive debugging.
debug = true;
logfile = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
};
logs = {
logs_collected = {
files = {
collect_list = [
{
file_path = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
log_group_name = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
log_stream_name = "{local_hostname}";
}
];
};
};
};
traces = {
local_mode = true;
traces_collected = {
xray = { };
};
};
};
mode = "onPremise";
};

# Keep the runtime directory for interactive debugging.
systemd.services.amazon-cloudwatch-agent.serviceConfig.RuntimeDirectoryPreserve = true;
};

testScript = ''
start_all()
machine.wait_for_unit("amazon-cloudwatch-agent.service")
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.pid")
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.toml")
# "config-translator" omits this file if no trace configurations are specified.
#
# See https://github.com/aws/amazon-cloudwatch-agent/issues/1320.
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.yaml")
machine.wait_for_file("/run/amazon-cloudwatch-agent/env-config.json")
'';
}
)
63 changes: 63 additions & 0 deletions pkgs/by-name/am/amazon-cloudwatch-agent/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
lib,
amazon-cloudwatch-agent,
buildGoModule,
fetchFromGitHub,
nix-update-script,
nixosTests,
stdenv,
versionCheckHook,
}:

buildGoModule rec {
pname = "amazon-cloudwatch-agent";
version = "1.300048.1";

src = fetchFromGitHub {
owner = "aws";
repo = "amazon-cloudwatch-agent";
rev = "refs/tags/v${version}";
hash = "sha256-zuiKRSUHvyXkBs5qUERA5mqoHbbRulyblyWRwBOu0nU=";
};

vendorHash = "sha256-czTG050V5bXsdU0nsN0an6XpXJClzpsGJJfIN7HNEAU=";

# See the list in https://github.com/aws/amazon-cloudwatch-agent/blob/v1.300048.1/Makefile#L68-L77.
subPackages = [
"cmd/config-downloader"
"cmd/config-translator"
"cmd/amazon-cloudwatch-agent"
# Broken since it hardcodes the package install path. See https://github.com/aws/amazon-cloudwatch-agent/issues/1319.
# "cmd/start-amazon-cloudwatch-agent"
"cmd/amazon-cloudwatch-agent-config-wizard"
];

# See https://github.com/aws/amazon-cloudwatch-agent/blob/v1.300048.1/Makefile#L57-L64.
#
# Needed for "amazon-cloudwatch-agent -version" to not show "Unknown".
postInstall = ''
echo v${version} > $out/bin/CWAGENT_VERSION
'';

doInstallCheck = true;

nativeInstallCheckInputs = [ versionCheckHook ];

versionCheckProgramArg = "-version";

passthru = {
tests = lib.optionalAttrs stdenv.isLinux {
inherit (nixosTests) amazon-cloudwatch-agent;
};

updateScript = nix-update-script { };
};

meta = {
description = "CloudWatch Agent enables you to collect and export host-level metrics and logs on instances running Linux or Windows server";
homepage = "https://github.com/aws/amazon-cloudwatch-agent";
license = lib.licenses.mit;
mainProgram = "amazon-cloudwatch-agent";
maintainers = with lib.maintainers; [ pmw ];
};
}

0 comments on commit 37cd2b9

Please sign in to comment.