Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

amazon-cloudwatch-agent: init at 1.300049.1 #337212

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2505.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

- [Kimai](https://www.kimai.org/), a web-based multi-user time-tracking application. Available as [services.kimai](option.html#opt-services.kimai).

- [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).

<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

## Backward Incompatibilities {#sec-release-25.05-incompatibilities}
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 @@ -877,6 +877,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 @@ -119,6 +119,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 = {
commiterate marked this conversation as resolved.
Show resolved Hide resolved
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")
commiterate marked this conversation as resolved.
Show resolved Hide resolved
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.300049.1";

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

vendorHash = "sha256-zsASHuTXL3brRlgLPNb4wFPHkYpUWbOdRDCXQUwZjIY=";

# 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 ];
};
commiterate marked this conversation as resolved.
Show resolved Hide resolved
}