diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..c63f97fd67 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "aws-otel-collector"] + path = aws-otel-collector + url = git@github.com:aws-observability/aws-otel-collector.git diff --git a/Makefile b/Makefile index 4be7b05460..44fbf4ebd1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ export BASE_SPACE=$(shell pwd) export BUILD_SPACE=$(BASE_SPACE)/build +export AOC_BASE_SPACE=$(BASE_SPACE)/aws-otel-collector +export AOC_BUILD_SPACE=$(AOC_BASE_SPACE)/build VERSION = $(shell echo `git describe --tag --dirty``git status --porcelain 2>/dev/null| grep -q "^??" &&echo '-untracked'`) VERSION := $(shell echo ${VERSION} | sed -e "s/^v//") @@ -14,9 +16,22 @@ LDFLAGS += -X github.com/aws/amazon-cloudwatch-agent/cfg/agentinfo.BuildStr=${B IMAGE = amazon/cloudwatch-agent:$(VERSION) DOCKER_BUILD_FROM_SOURCE = docker build -t $(IMAGE) -f ./amazon-cloudwatch-container-insights/cloudwatch-agent-dockerfile/source/Dockerfile +AOC_IMPORT_PATH=github.com/aws-observability/aws-otel-collector +AOC_GIT_SHA = $(shell cd $(AOC_BASE_SPACE) && git rev-parse HEAD) +AOC_LDFLAGS = -s -w -X $(AOC_IMPORT_PATH)/tools/version.GitHash=$(AOC_GIT_SHA) +AOC_LDFLAGS += -X github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter.collectorDistribution=cwagent-otel-collector +AOC_LDFLAGS += -X github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsemfexporter.collectorDistribution=cwagent-otel-collector +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/tools/version.Version=$(VERSION) +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/tools/version.Date=$(BUILD) +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/pkg/userutils.defaultUser=cwagent +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/pkg/logger.UnixLogPath=/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs/cwagent-otel-collector.log +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/pkg/logger.WindowsLogPath=C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\CWAgentOtelCollector\\Logs\\cwagent-otel-collector.log +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/pkg/extraconfig.unixExtraConfigPath=/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/extracfg.txt +AOC_LDFLAGS += -X $(AOC_IMPORT_PATH)/pkg/extraconfig.windowsExtraConfigPath=C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\CWAgentOtelCollector\\extracfg.txt + release: clean test build package-rpm package-deb package-win -build: check_secrets amazon-cloudwatch-agent config-translator start-amazon-cloudwatch-agent amazon-cloudwatch-agent-config-wizard config-downloader +build: check_secrets cwagent-otel-collector amazon-cloudwatch-agent config-translator start-amazon-cloudwatch-agent amazon-cloudwatch-agent-config-wizard config-downloader check_secrets:: if grep --exclude-dir=build --exclude-dir=vendor -E "(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}|(\"|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)(\"|')?\\s*(:|=>|=)\\s*(\"|')?[A-Za-z0-9/\\+=]{40}(\"|')?" -Rn .; then echo "check_secrets failed"; exit 1; fi; @@ -36,6 +51,12 @@ amazon-cloudwatch-agent: copy-version-file GOOS=linux GOARCH=arm64 go build -ldflags="${LDFLAGS}" -o $(BUILD_SPACE)/bin/linux_arm64/amazon-cloudwatch-agent github.com/aws/amazon-cloudwatch-agent/cmd/amazon-cloudwatch-agent GOOS=windows GOARCH=amd64 go build -ldflags="${LDFLAGS}" -o $(BUILD_SPACE)/bin/windows_amd64/amazon-cloudwatch-agent.exe github.com/aws/amazon-cloudwatch-agent/cmd/amazon-cloudwatch-agent +cwagent-otel-collector: + @echo Building aws-otel-collector + cd $(AOC_BASE_SPACE) && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="${AOC_LDFLAGS}" -o $(BUILD_SPACE)/bin/linux_amd64/cwagent-otel-collector $(AOC_IMPORT_PATH)/cmd/awscollector + cd $(AOC_BASE_SPACE) && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="${AOC_LDFLAGS}" -o $(BUILD_SPACE)/bin/linux_arm64/cwagent-otel-collector $(AOC_IMPORT_PATH)/cmd/awscollector + cd $(AOC_BASE_SPACE) && CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="${AOC_LDFLAGS}" -o $(BUILD_SPACE)/bin/windows_amd64/cwagent-otel-collector.exe $(AOC_IMPORT_PATH)/cmd/awscollector + config-translator: copy-version-file @echo Building config-translator CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="${LDFLAGS}" -o $(BUILD_SPACE)/bin/linux_amd64/config-translator github.com/aws/amazon-cloudwatch-agent/cmd/config-translator @@ -82,6 +103,9 @@ package-prepare-rpm: cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.conf $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.spec $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/translator/config/schema.json $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/amazon-cloudwatch-agent-schema.json + cp $(BASE_SPACE)/packaging/dependencies/cwagent-otel-collector.service $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/ + cp $(BASE_SPACE)/packaging/linux/cwagent-otel-collector.conf $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/ + cp $(AOC_BASE_SPACE)/config.yaml $(BUILD_SPACE)/private/linux/amd64/rpm/amazon-cloudwatch-agent-pre-pkg/predefined-config-data # arm64 rpm mkdir -p $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg @@ -97,6 +121,9 @@ package-prepare-rpm: cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.conf $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.spec $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/translator/config/schema.json $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/amazon-cloudwatch-agent-schema.json + cp $(BASE_SPACE)/packaging/dependencies/cwagent-otel-collector.service $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/ + cp $(BASE_SPACE)/packaging/linux/cwagent-otel-collector.conf $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/ + cp $(AOC_BASE_SPACE)/config.yaml $(BUILD_SPACE)/private/linux/arm64/rpm/amazon-cloudwatch-agent-pre-pkg/predefined-config-data cp -rf $(BASE_SPACE)/Tools $(BUILD_SPACE)/ package-prepare-deb: @@ -113,6 +140,9 @@ package-prepare-deb: cp $(BASE_SPACE)/cfg/commonconfig/common-config.toml $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.conf $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/translator/config/schema.json $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/amazon-cloudwatch-agent-schema.json + cp $(BASE_SPACE)/packaging/dependencies/cwagent-otel-collector.service $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/ + cp $(BASE_SPACE)/packaging/linux/cwagent-otel-collector.conf $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/ + cp $(AOC_BASE_SPACE)/config.yaml $(BUILD_SPACE)/private/linux/amd64/deb/amazon-cloudwatch-agent-pre-pkg/predefined-config-data # arm64 deb mkdir -p $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg @@ -127,6 +157,9 @@ package-prepare-deb: cp $(BASE_SPACE)/cfg/commonconfig/common-config.toml $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.conf $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/translator/config/schema.json $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/amazon-cloudwatch-agent-schema.json + cp $(BASE_SPACE)/packaging/dependencies/cwagent-otel-collector.service $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/ + cp $(BASE_SPACE)/packaging/linux/cwagent-otel-collector.conf $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/ + cp $(AOC_BASE_SPACE)/config.yaml $(BUILD_SPACE)/private/linux/arm64/deb/amazon-cloudwatch-agent-pre-pkg/predefined-config-data cp -rf $(BASE_SPACE)/Tools $(BUILD_SPACE)/ cp -rf $(BASE_SPACE)/packaging $(BUILD_SPACE)/ @@ -140,11 +173,11 @@ package-prepare-win-zip: cp $(BASE_SPACE)/RELEASE_NOTES $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ cp $(BUILD_SPACE)/bin/CWAGENT_VERSION $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/cfg/commonconfig/common-config.toml $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ - cp $(BASE_SPACE)/packaging/linux/amazon-cloudwatch-agent.conf $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ cp $(BASE_SPACE)/translator/config/schema.json $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/amazon-cloudwatch-agent-schema.json cp ${BASE_SPACE}/packaging/windows/amazon-cloudwatch-agent-ctl.ps1 $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ cp ${BASE_SPACE}/packaging/windows/install.ps1 $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ cp ${BASE_SPACE}/packaging/windows/uninstall.ps1 $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/ + cp $(AOC_BASE_SPACE)/config.yaml $(BUILD_SPACE)/private/windows/amd64/zip/amazon-cloudwatch-agent-pre-pkg/predefined-config-data cp -rf $(BASE_SPACE)/Tools $(BUILD_SPACE)/ .PHONY: package-rpm @@ -171,4 +204,4 @@ dockerized-build: # Use vendor instead of proxy when building w/ vendor folder dockerized-build-vendor: - $(DOCKER_BUILD_FROM_SOURCE) --build-arg GO111MODULE=off . \ No newline at end of file + $(DOCKER_BUILD_FROM_SOURCE) --build-arg GO111MODULE=off . diff --git a/README.md b/README.md index 2c8ade8afa..7cab7c823b 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Amazon Cloudwatch Agent uses the open-source project [telegraf](https://github.c ``` sudo yum install -y rpmdevtools rpm-build ``` +* Run `git submodule init && git submodule update` to fetch the code of aws-otel-collector + * Run `make build` to build the Cloudwatch Agent for Linux, Debian, Windows environment. * Run `make release` to build the agent. This also packages it into a RPM, DEB and ZIP package. diff --git a/THIRD-PARTY b/THIRD-PARTY index 5996927ded..0b07c6b2fd 100644 --- a/THIRD-PARTY +++ b/THIRD-PARTY @@ -202,6 +202,8 @@ END OF TERMS AND CONDITIONS https://github.com/googleapis/google-cloud-go ** contrib.go.opencensus.io/exporter/ocagent; version v0.6.0 -- https://github.com/census-ecosystem/opencensus-go-exporter-ocagent +** github.com/aws-observability/aws-otel-collector; version 0.6.0 -- +https://github.com/aws-observability/aws-otel-collector ** github.com/aws/aws-lambda-go; version v1.13.3 -- https://github.com/aws/aws-lambda-go ** github.com/aws/aws-sdk-go; version 1.30.15 -- @@ -618,6 +620,9 @@ limitations under the License. Copyright 2018 Google LLC * For contrib.go.opencensus.io/exporter/ocagent see also this required NOTICE: Copyright 2018, OpenCensus Authors +* For github.com/aws-observability/aws-otel-collector see also this required +NOTICE: + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * For github.com/aws/aws-lambda-go see also this required NOTICE: Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/Tools/src/create_deb.sh b/Tools/src/create_deb.sh index ac6e24e2bf..78dbcb3049 100755 --- a/Tools/src/create_deb.sh +++ b/Tools/src/create_deb.sh @@ -12,11 +12,12 @@ echo "Creating debian folders" mkdir -p ${BUILD_SPACE}/bin/linux/${ARCH}/ mkdir -p ${BUILD_ROOT}/bin mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/logs -mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin -mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/etc -mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d -mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/manager mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/var +mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d +mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs +mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var +mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.d +mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin mkdir -p ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/doc mkdir -p ${BUILD_ROOT}/etc/init mkdir -p ${BUILD_ROOT}/etc/systemd/system/ @@ -28,15 +29,19 @@ cp ${PREPKGPATH}/THIRD-PARTY-LICENSES ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-ag cp ${PREPKGPATH}/RELEASE_NOTES ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/CWAGENT_VERSION ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/amazon-cloudwatch-agent ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ +cp ${PREPKGPATH}/cwagent-otel-collector ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/amazon-cloudwatch-agent-ctl ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/amazon-cloudwatch-agent.service ${BUILD_ROOT}/etc/systemd/system/ +cp ${PREPKGPATH}/cwagent-otel-collector.service ${BUILD_ROOT}/etc/systemd/system/ cp ${PREPKGPATH}/config-translator ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/config-downloader ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/amazon-cloudwatch-agent-config-wizard ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/start-amazon-cloudwatch-agent ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/ cp ${PREPKGPATH}/common-config.toml ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/etc/ -cp ${PREPKGPATH}/amazon-cloudwatch-agent.conf ${BUILD_ROOT}/etc/init/amazon-cloudwatch-agent.conf +cp ${PREPKGPATH}/amazon-cloudwatch-agent.conf ${BUILD_ROOT}/etc/init/ +cp ${PREPKGPATH}/cwagent-otel-collector.conf ${BUILD_ROOT}/etc/init/ cp ${PREPKGPATH}/amazon-cloudwatch-agent-schema.json ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/doc/ +cp ${PREPKGPATH}/predefined-config-data ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var/.predefined-config-data ############################# create the symbolic links here to make them managed by dpkg # bin @@ -45,20 +50,25 @@ ln -f -s /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl ${BUIL # etc mkdir -p ${BUILD_ROOT}/etc/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/etc ${BUILD_ROOT}/etc/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc ${BUILD_ROOT}/etc/amazon/cwagent-otel-collector # log mkdir -p ${BUILD_ROOT}/var/log/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/logs ${BUILD_ROOT}/var/log/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs ${BUILD_ROOT}/var/log/amazon/cwagent-otel-collector # pid mkdir -p ${BUILD_ROOT}/var/run/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/var ${BUILD_ROOT}/var/run/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var ${BUILD_ROOT}/var/run/amazon/cwagent-otel-collector cp ${BUILD_SPACE}/packaging/debian/conffiles ${BUILD_ROOT}/ cp ${BUILD_SPACE}/packaging/debian/preinst ${BUILD_ROOT}/ cp ${BUILD_SPACE}/packaging/debian/prerm ${BUILD_ROOT}/ +cp ${BUILD_SPACE}/packaging/debian/postinst ${BUILD_ROOT}/ cp ${BUILD_SPACE}/packaging/debian/debian-binary ${BUILD_ROOT}/ chmod ug+rx ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent +chmod ug+rx ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector chmod ug+rx ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl chmod ug+rx ${BUILD_ROOT}/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent @@ -76,7 +86,7 @@ cd ${BUILD_ROOT}/..; find ./debian -type d | xargs chmod 755; cd ~- # the below permissioning is required by debian cd ${BUILD_ROOT}; tar czf data.tar.gz opt etc usr var --owner=0 --group=0 ; cd ~- -cd ${BUILD_ROOT}; tar czf control.tar.gz control conffiles preinst prerm --owner=0 --group=0 ; cd ~- +cd ${BUILD_ROOT}; tar czf control.tar.gz control conffiles preinst prerm postinst --owner=0 --group=0 ; cd ~- echo "Creating the debian package" echo "Constructing the deb packagage" diff --git a/Tools/src/create_rpm.sh b/Tools/src/create_rpm.sh index 784ff5848b..bd66fced14 100755 --- a/Tools/src/create_rpm.sh +++ b/Tools/src/create_rpm.sh @@ -15,11 +15,12 @@ echo "Creating rpm-build workspace" mkdir -p ${BUILD_SPACE}/bin/linux/${ARCH}/ mkdir -p ${BUILD_ROOT}/{RPMS,SRPMS,BUILD,SOURCES,SPECS,BUILDROOT} mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/logs -mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin -mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/etc -mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d -mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/manager mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/var +mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d +mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs +mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var +mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.d +mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin mkdir -p ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/doc mkdir -p ${BUILD_ROOT}/SOURCES/etc/init mkdir -p ${BUILD_ROOT}/SOURCES/etc/systemd/system/ @@ -41,10 +42,16 @@ cp ${PREPKGPATH}/start-amazon-cloudwatch-agent ${BUILD_ROOT}/SOURCES/opt/aws/ama cp ${PREPKGPATH}/common-config.toml ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/etc/ cp ${PREPKGPATH}/amazon-cloudwatch-agent.conf ${BUILD_ROOT}/SOURCES/etc/init/amazon-cloudwatch-agent.conf cp ${PREPKGPATH}/amazon-cloudwatch-agent-schema.json ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/doc/ +cp ${PREPKGPATH}/cwagent-otel-collector ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin/ +cp ${PREPKGPATH}/cwagent-otel-collector.service ${BUILD_ROOT}/SOURCES/etc/systemd/system/ +cp ${PREPKGPATH}/cwagent-otel-collector.conf ${BUILD_ROOT}/SOURCES/etc/init/ +cp ${PREPKGPATH}/predefined-config-data ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var/.predefined-config-data + chmod ug+rx ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent chmod ug+rx ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl chmod ug+rx ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent +chmod ug+rx ${BUILD_ROOT}/SOURCES/opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector tar -zcvf ${BUILD_ROOT}/SOURCES/amazon-cloudwatch-agent.tar.gz -C ${BUILD_ROOT}/SOURCES opt etc rm -rf ${BUILD_ROOT}/SOURCES/opt ${BUILD_ROOT}/SOURCES/etc diff --git a/Tools/src/create_win.sh b/Tools/src/create_win.sh index 29647c22ef..80c42a94e4 100755 --- a/Tools/src/create_win.sh +++ b/Tools/src/create_win.sh @@ -9,7 +9,7 @@ AGENT_VERSION=`cat ${PREPKGPATH}/CWAGENT_VERSION` echo "BUILD_SPACE: ${BUILD_SPACE} agent_version: ${AGENT_VERSION} pre-package location:${PREPKGPATH}" echo "Creating windows folders" -mkdir -p "${BUILD_SPACE}/private/windows_${ARCH}/amazon-cloudwatch-agent" +mkdir -p "${BUILD_ROOT}/amazon-cloudwatch-agent" mkdir -p ${BUILD_SPACE}/bin/windows/${ARCH}/ echo "Copying application files" @@ -20,6 +20,7 @@ cp ${PREPKGPATH}/THIRD-PARTY-LICENSES ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/RELEASE_NOTES ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/CWAGENT_VERSION ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/amazon-cloudwatch-agent.exe ${BUILD_ROOT}/amazon-cloudwatch-agent/ +cp ${PREPKGPATH}/cwagent-otel-collector.exe ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/amazon-cloudwatch-agent-ctl.ps1 ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/install.ps1 ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/uninstall.ps1 ${BUILD_ROOT}/amazon-cloudwatch-agent/ @@ -29,6 +30,7 @@ cp ${PREPKGPATH}/amazon-cloudwatch-agent-config-wizard.exe ${BUILD_ROOT}/amazon- cp ${PREPKGPATH}/start-amazon-cloudwatch-agent.exe ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/common-config.toml ${BUILD_ROOT}/amazon-cloudwatch-agent/ cp ${PREPKGPATH}/amazon-cloudwatch-agent-schema.json ${BUILD_ROOT}/amazon-cloudwatch-agent/ +cp ${PREPKGPATH}/predefined-config-data ${BUILD_ROOT}/amazon-cloudwatch-agent/ echo "Constructing the zip package" diff --git a/aws-otel-collector b/aws-otel-collector new file mode 160000 index 0000000000..8a5d0b7412 --- /dev/null +++ b/aws-otel-collector @@ -0,0 +1 @@ +Subproject commit 8a5d0b741205e6062310a0d2465a53aead12d023 diff --git a/cmd/config-downloader/downloader.go b/cmd/config-downloader/downloader.go index 8587c06bcc..6174e1a5c7 100644 --- a/cmd/config-downloader/downloader.go +++ b/cmd/config-downloader/downloader.go @@ -224,7 +224,7 @@ func main() { if err := os.Remove(outputFilePath); err != nil { panic(fmt.Sprintf("Failed to remove the json file %v: %v", outputFilePath, err)) } else { - fmt.Printf("Successfully removed the config file %s", outputFilePath) + fmt.Printf("Successfully removed the config file %s\n", outputFilePath) } } } diff --git a/licensing/THIRD-PARTY-LICENSES b/licensing/THIRD-PARTY-LICENSES index 5996927ded..0b07c6b2fd 100644 --- a/licensing/THIRD-PARTY-LICENSES +++ b/licensing/THIRD-PARTY-LICENSES @@ -202,6 +202,8 @@ END OF TERMS AND CONDITIONS https://github.com/googleapis/google-cloud-go ** contrib.go.opencensus.io/exporter/ocagent; version v0.6.0 -- https://github.com/census-ecosystem/opencensus-go-exporter-ocagent +** github.com/aws-observability/aws-otel-collector; version 0.6.0 -- +https://github.com/aws-observability/aws-otel-collector ** github.com/aws/aws-lambda-go; version v1.13.3 -- https://github.com/aws/aws-lambda-go ** github.com/aws/aws-sdk-go; version 1.30.15 -- @@ -618,6 +620,9 @@ limitations under the License. Copyright 2018 Google LLC * For contrib.go.opencensus.io/exporter/ocagent see also this required NOTICE: Copyright 2018, OpenCensus Authors +* For github.com/aws-observability/aws-otel-collector see also this required +NOTICE: + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * For github.com/aws/aws-lambda-go see also this required NOTICE: Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packaging/debian/cwagent-otel-collector.conf b/packaging/debian/cwagent-otel-collector.conf new file mode 100644 index 0000000000..bcb4b07272 --- /dev/null +++ b/packaging/debian/cwagent-otel-collector.conf @@ -0,0 +1,15 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT + +description "CWAgent OTel Collector" +author "Amazon.com" + +start on (runlevel [2345] and started network) +stop on (runlevel [!2345] or stopping network) + +normal exit 0 + +respawn + +exec /opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector --config /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.yaml +post-stop exec sleep 1 diff --git a/packaging/debian/postinst b/packaging/debian/postinst new file mode 100644 index 0000000000..511643c6b1 --- /dev/null +++ b/packaging/debian/postinst @@ -0,0 +1,4 @@ +#! /bin/bash + +chown -R cwagent:cwagent /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs +chown -R cwagent:cwagent /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var diff --git a/packaging/dependencies/amazon-cloudwatch-agent-ctl b/packaging/dependencies/amazon-cloudwatch-agent-ctl index a4c9ff529a..e1a82370af 100755 --- a/packaging/dependencies/amazon-cloudwatch-agent-ctl +++ b/packaging/dependencies/amazon-cloudwatch-agent-ctl @@ -9,23 +9,33 @@ set -u readonly AGENTDIR="/opt/aws/amazon-cloudwatch-agent" readonly CMDDIR="${AGENTDIR}/bin" readonly CONFDIR="${AGENTDIR}/etc" -readonly LOGDIR="${AGENTDIR}/logs" -readonly RESTART_FILE="${CONFDIR}/restart" +readonly CWOC_CONFDIR="${AGENTDIR}/cwagent-otel-collector/etc" +readonly CWA_RESTART_FILE="${CONFDIR}/restart" +readonly CWOC_RESTART_FILE="${CWOC_CONFDIR}/cwoc-restart" readonly VERSION_FILE="${CMDDIR}/CWAGENT_VERSION" # The systemd and upstart scripts assume exactly this .toml file name readonly TOML="${CONFDIR}/amazon-cloudwatch-agent.toml" +readonly YAML="${CWOC_CONFDIR}/cwagent-otel-collector.yaml" readonly JSON="${CONFDIR}/amazon-cloudwatch-agent.json" readonly JSON_DIR="${CONFDIR}/amazon-cloudwatch-agent.d" +readonly YAML_DIR="${CWOC_CONFDIR}/cwagent-otel-collector.d" +readonly PREDEFINED_CONFIG_DATA="${AGENTDIR}/cwagent-otel-collector/var/.predefined-config-data" readonly CV_LOG_FILE="${AGENTDIR}/logs/configuration-validation.log" readonly COMMON_CONIG="${CONFDIR}/common-config.toml" +readonly CWA_NAME='amazon-cloudwatch-agent' +readonly CWOC_NAME='cwagent-otel-collector' +readonly ALL_CONFIG='all' + SYSTEMD='false' UsageString=" - usage: amazon-cloudwatch-agent-ctl -a stop|start|status|fetch-config|append-config|remove-config [-m ec2|onPremise|auto] [-c default|ssm:|file:] [-s] + usage: amazon-cloudwatch-agent-ctl -a + stop|start|status|fetch-config|append-config|remove-config [-m + ec2|onPremise|auto] [-c default|all|ssm:|file:] [-o default|all|ssm:|file:] [-s] e.g. 1. apply a SSM parameter store config on EC2 instance and restart the agent afterwards: @@ -39,210 +49,401 @@ UsageString=" stop: stop the agent process. start: start the agent process. status: get the status of the agent process. - fetch-config: use this json config as the agent's only configuration. - append-config: append json config with the existing json configs if any. - remove-config: remove json config based on the location (ssm parameter store name, file name) + fetch-config: apply config for agent, followed by -c or -o or both. Target config can be based on location (ssm parameter store name, file name), or 'default'. + append-config: append json config with the existing json configs if any, followed by -c. Target config can be based on the location (ssm parameter store name, file name), or 'default'. + remove-config: remove config for agent, followed by -c or -o or both. Target config can be based on the location (ssm parameter store name, file name), or 'all'. -m: mode ec2: indicate this is on ec2 host. onPremise: indicate this is on onPremise host. auto: use ec2 metadata to determine the environment, may not be accurate if ec2 metadata is not available for some reason on EC2. - -c: configuration + -c: amazon-cloudwatch-agent configuration + default: default configuration for quick trial. + ssm:: ssm parameter store name. + file:: file path on the host. + all: all existing configs. Only apply to remove-config action. + + -o: cwagent-otel-collector configuration default: default configuration for quick trial. - ssm:: ssm parameter store name - file:: file path on the host + ssm:: ssm parameter store name. + file:: file path on the host. + all: all existing configs. Only apply to remove-config action. -s: optionally restart after configuring the agent configuration this parameter is used for 'fetch-config', 'append-config', 'remove-config' action only. " -cwa_start() { +start_all() { mode="${1:-}" - if [ "$(cwa_runstatus)" = 'running' ]; then + echo "****** processing cwagent-otel-collector ******" + set +e + agent_start "${CWOC_NAME}" "${mode}" + set -e + + echo "" + echo "****** processing amazon-cloudwatch-agent ******" + agent_start "${CWA_NAME}" "${mode}" +} + +agent_start() { + agent_name="${1:-}" + mode="${2:-}" + + if [ "$(runstatus ${agent_name})" = 'running' ]; then + echo "${agent_name} has already been started" return 0 fi - if [ ! -f "${TOML}" ]; then - echo "amazon-cloudwatch-agent is not configured. Applying default configuration before starting it." - cwa_config 'default' 'false' "${mode}" + if [ "${agent_name}" = "${CWOC_NAME}" ] && [ ! -f "${YAML}" ]; then + echo "${CWOC_NAME} will not be started as it has not been configured yet." + return 0 + fi + + if [ "${agent_name}" = "${CWA_NAME}" ] && [ ! -f "${TOML}" ]; then + if [ -f "${YAML}" ]; then + # If cwagent-otel-collector config exists, amazon-cloudwatch-agent default config will be suppressed + echo "${CWA_NAME} will not be started as it has not been configured yet." + return 0 + fi + echo "Both ${CWA_NAME} and ${CWOC_NAME} are not configured. Applying amazon-cloudwatch-agent default configuration." + cwa_config 'default' 'false' "${mode}" 'default' fi + if [ "${SYSTEMD}" = 'true' ]; then - systemctl daemon-reload - systemctl enable amazon-cloudwatch-agent.service - service amazon-cloudwatch-agent restart + systemctl daemon-reload || return + systemctl enable "${agent_name}.service" || return + service "${agent_name}" restart || return else - start amazon-cloudwatch-agent - sleep 1 + start "${agent_name}" || return + sleep 1 fi } -cwa_stop() { - if [ "$(cwa_runstatus)" = 'stopped' ]; then +stop_all() { + echo "****** processing cwagent-otel-collector ******" + set +e + agent_stop "${CWOC_NAME}" + set -e + + echo "" + echo "****** processing amazon-cloudwatch-agent ******" + agent_stop "${CWA_NAME}" +} + +agent_stop() { + agent_name="${1:-}" + + if [ "$(runstatus ${agent_name})" = 'stopped' ]; then + echo "${agent_name} has already been stopped" return 0 fi if [ "${SYSTEMD}" = 'true' ]; then - service amazon-cloudwatch-agent stop + service "${agent_name}" stop || return else - stop amazon-cloudwatch-agent || true + stop "${agent_name}" || return fi } # support for restart during upgrade via SSM packages -cwa_prep_restart() { - if [ "$(cwa_runstatus)" = 'running' ]; then - touch "$RESTART_FILE" +prep_restart_all() { + set +e + agent_prep_restart "${CWOC_NAME}" "${CWOC_RESTART_FILE}" + set -e + + agent_prep_restart "${CWA_NAME}" "${CWA_RESTART_FILE}" +} + +agent_prep_restart() { + agent_name="${1:-}" + restart_file="${2:-}" + if [ "$(runstatus ${agent_name})" = 'running' ]; then + touch "${restart_file}" fi } # support for restart during upgrade via SSM packages -cwa_cond_restart() { - if [ -f "${RESTART_FILE}" ]; then - cwa_start - rm -f "${RESTART_FILE}" - fi +cond_restart_all() { + set +e + agent_cond_restart "${CWOC_NAME}" "${CWOC_RESTART_FILE}" + set -e + + agent_cond_restart "${CWA_NAME}" "${CWA_RESTART_FILE}" } -cwa_preun() { - cwa_stop - if [ "${SYSTEMD}" = 'true' ]; then - systemctl disable amazon-cloudwatch-agent.service - systemctl daemon-reload - systemctl reset-failed +agent_cond_restart() { + agent_name="${1:-}" + restart_file="${2:-}" + if [ -f "${restart_file}" ]; then + agent_start "${agent_name}" + rm -f "${restart_file}" fi } -cwa_status() { +preun_all() { + set +e + agent_preun "${CWOC_NAME}" + set -e + + agent_preun "${CWA_NAME}" +} - pid='' +agent_preun() { + agent_name="${1:-}" + agent_stop "${agent_name}" if [ "${SYSTEMD}" = 'true' ]; then - pid="$(systemctl show -p MainPID amazon-cloudwatch-agent.service | sed s/MainPID=//)" - else - pid="$(initctl status amazon-cloudwatch-agent | sed -n s/^.*process\ //p)" + systemctl disable "${agent_name}.service" || return + systemctl daemon-reload || return + systemctl reset-failed || return fi +} - starttime_fmt='' - if [ ${pid} ] && [ ${pid} -ne 0 ]; then - starttime="$(TZ=UTC ps -o lstart= "${pid}")" - starttime_fmt="$(TZ=UTC date -Isec -d "${starttime}")" +status_all() { + cwa_config_status='configured' + if [ ! -f "${TOML}" ]; then + cwa_config_status='not configured' + fi + + cwoc_config_status='configured' + if [ ! -f "${YAML}" ]; then + cwoc_config_status='not configured' fi version="$(cat ${VERSION_FILE})" echo "{" - echo " \"status\": \"$(cwa_runstatus)\"," - echo " \"starttime\": \"${starttime_fmt}\"," + echo " \"status\": \"$(runstatus ${CWA_NAME})\"," + echo " \"starttime\": \"$(get_starttime_fmt ${CWA_NAME})\"," + echo " \"configstatus\": \"${cwa_config_status}\"," + echo " \"cwoc_status\": \"$(runstatus ${CWOC_NAME})\"," + echo " \"cwoc_starttime\": \"$(get_starttime_fmt ${CWOC_NAME})\"," + echo " \"cwoc_configstatus\": \"${cwoc_config_status}\"," echo " \"version\": \"${version}\"" echo "}" } -cwa_runstatus() { +get_starttime_fmt() { + agent_name="${1:-}" + + agentPid='' + if [ "${SYSTEMD}" = 'true' ]; then + agentPid="$(systemctl show -p MainPID "${agent_name}.service" | sed s/MainPID=//)" + else + agentPid="$(initctl status "${agent_name}" | sed -n s/^.*process\ //p)" + fi + + starttime_fmt='' + if [ "${agentPid}" ] && [ "${agentPid}" -ne "0" ]; then + starttime="$(TZ=UTC ps -o lstart= "${agentPid}")" + starttime_fmt="$(TZ=UTC date -Isec -d "${starttime}")" + fi + + echo "${starttime_fmt}" +} + +runstatus() { + agent_name="${1:-}" + running=false if [ "${SYSTEMD}" = 'true' ]; then - set +e - if systemctl is-active amazon-cloudwatch-agent.service 1>/dev/null; then - running='true' - fi - set -e + set +e + if systemctl is-active "${agent_name}.service" 1>/dev/null; then + running='true' + fi + set -e else - if [ "$(initctl status amazon-cloudwatch-agent | grep -c running)" = 1 ]; then - running='true' - fi + if [ "$(initctl status "${agent_name}" | grep -c running)" = 1 ]; then + running='true' + fi fi if [ "${running}" = 'true' ]; then - echo "running" + echo "running" else - echo "stopped" + echo "stopped" fi } -cwa_config() { - config_location="${1:-}" - restart="${2:-}" - mode="${3:-}" - multi_config="${4:-default}" +config_all() { + cwa_config_location="${1:-}" + cwoc_config_location="${2:-}" + restart="${3:-}" + mode="${4:-}" + multi_config="${5:-}" + + if [ -z "${cwa_config_location}" ] && [ -z "${cwoc_config_location}" ]; then + cwa_config_location='default' + fi mkdir -p "${CONFDIR}" param_mode="ec2" case "${mode}" in - ec2) - param_mode="ec2" - ;; - onPremise) - param_mode="onPrem" - ;; - auto) - param_mode="auto" - ;; - *) echo "Invalid mode: ${mode}" >&2 - exit 1 - ;; + ec2) + param_mode="ec2" + ;; + onPremise) + param_mode="onPrem" + ;; + auto) + param_mode="auto" + ;; + *) echo "Invalid mode: ${mode}" >&2 + exit 1 + ;; esac - runDownloaderCommand="${CMDDIR}/config-downloader --output-dir ${JSON_DIR} --download-source ${config_location} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config}" - runTranslatorCommand="${CMDDIR}/config-translator --input ${JSON} --input-dir ${JSON_DIR} --output ${TOML} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config}" - runAgentSchemaTestCommand="${CMDDIR}/amazon-cloudwatch-agent -schematest -config ${TOML}" + if [ -n "${cwoc_config_location}" ]; then + echo "****** processing cwagent-otel-collector ******" + set +e + cwoc_config "${cwoc_config_location}" "${restart}" "${param_mode}" "${multi_config}" + set -e + echo "" + fi - echo ${runDownloaderCommand} - ${runDownloaderCommand} + # cwa_config is called after cwoc_config becuase that whether applying + # default cwa config depends on the existence of cwoc config + if [ -n "${cwa_config_location}" ]; then + echo "****** processing amazon-cloudwatch-agent ******" + cwa_config "${cwa_config_location}" "${restart}" "${param_mode}" "${multi_config}" + fi +} - echo "Start configuration validation..." - echo ${runTranslatorCommand} - ${runTranslatorCommand} +cwa_config() { + cwa_config_location="${1:-}" + restart="${2:-}" + param_mode="${3:-}" + multi_config="${4:-}" - echo ${runAgentSchemaTestCommand} - # We will redirect the verbose error message out - if ! ${runAgentSchemaTestCommand} > ${CV_LOG_FILE} 2>&1; then - echo "Configuration validation second phase failed" - echo "======== Error Log ========" - cat ${CV_LOG_FILE} - exit 1 + if [ "${cwa_config_location}" = "${ALL_CONFIG}" ] && [ "${multi_config}" != 'remove' ]; then + echo "ignore cwa configuration \"${ALL_CONFIG}\" as it is only supported by action \"remove-config\"" + return + fi + + if [ "${cwa_config_location}" = "${ALL_CONFIG}" ]; then + rm -rf "${JSON_DIR}"/* + else + runDownloaderCommand="${CMDDIR}/config-downloader --output-dir ${JSON_DIR} --download-source ${cwa_config_location} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config}" + echo "${runDownloaderCommand}" + ${runDownloaderCommand} || return + fi + + if [ ! "$(ls ${JSON_DIR})" ]; then + echo "all amazon-cloudwatch-agent configurations have been removed" + rm -f "${TOML}" + else + echo "Start configuration validation..." + runTranslatorCommand="${CMDDIR}/config-translator --input ${JSON} --input-dir ${JSON_DIR} --output ${TOML} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config}" + echo "${runTranslatorCommand}" + ${runTranslatorCommand} || return + + runAgentSchemaTestCommand="${CMDDIR}/amazon-cloudwatch-agent -schematest -config ${TOML}" + echo "${runAgentSchemaTestCommand}" + # We will redirect the verbose error message out + if ! ${runAgentSchemaTestCommand} > ${CV_LOG_FILE} 2>&1; then + echo "Configuration validation second phase failed" + echo "======== Error Log ========" + cat ${CV_LOG_FILE} + exit 1 + fi + echo "Configuration validation second phase succeeded" + echo "Configuration validation succeeded" + + chmod ug+rw "${TOML}" + + # for translator: + # default: only process .tmp files + # append: process both existing files and .tmp files + # remove: only process existing files + # At this point, all json configs have been validated + # multi_config: + # default: delete non .tmp file, rename .tmp file + # append: rename .tmp file + # remove: no-op + if [ "${multi_config}" = 'default' ]; then + rm -f "${JSON}" + for file in "${JSON_DIR}"/*; do + base="${JSON_DIR}/$(basename "${file}" .tmp)" + if [ "${file}" = "${base}" ]; then + rm -f "${file}" + else + mv -f "${file}" "${base}" + fi + done + elif [ "${multi_config}" = 'append' ]; then + for file in "${JSON_DIR}"/*.tmp; do + mv -f "${file}" "${JSON_DIR}/$(basename "${file}" .tmp)" + done + fi + fi + + if [ "${restart}" = 'true' ]; then + agent_stop "${CWA_NAME}" + agent_start "${CWA_NAME}" "${param_mode}" fi - echo "Configuration validation second phase succeeded" - echo "Configuration validation succeeded" - - chmod ug+rw "${TOML}" - - # for translator: - # default: only process .tmp files - # append: process both existing files and .tmp files - # remove: only process existing files - # At this point, all json configs have been validated - # multi_config: - # default: delete non .tmp file, rename .tmp file - # append: rename .tmp file - # remove: no-op - if [ "${multi_config}" = 'default' ]; then - rm -f "${JSON}" - for file in "${JSON_DIR}"/*; do - base="${JSON_DIR}/$(basename "${file}" .tmp)" +} + +cwoc_config() { + cwoc_config_location="${1:-}" + restart="${2:-}" + param_mode="${3:-}" + multi_config="${4:-}" + + if [ -f /opt/aws/aws-otel-collector/bin/aws-otel-collector-ctl ]; then + echo "REMINDER: you are configuring \"cwagent-otel-collector\" instead of \"aws-otel-collector\"." + fi + + if [ "${multi_config}" = 'append' ]; then + echo "ignore \"-o\" as cwagent-otel-collector doesn't support append-config" + return 0 + fi + + if [ "${cwoc_config_location}" = "${ALL_CONFIG}" ] && [ "${multi_config}" != 'remove' ]; then + echo "ignore cwoc configuration \"${ALL_CONFIG}\" as it is only supported by action \"remove-config\"" + return + fi + + if [ "${cwoc_config_location}" = "${ALL_CONFIG}" ]; then + rm -rf "${YAML_DIR}"/* + elif [ "${multi_config}" = 'default' ] && [ "${cwoc_config_location}" = 'default' ]; then + cp "${PREDEFINED_CONFIG_DATA}" "${YAML_DIR}/default.tmp" + echo "Successfully fetched the config and saved in ${YAML_DIR}/default.tmp" + else + runDownloaderCommand="${CMDDIR}/config-downloader --output-dir ${YAML_DIR} --download-source ${cwoc_config_location} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config}" + echo "${runDownloaderCommand}" + ${runDownloaderCommand} || return + fi + + if [ ! "$(ls ${YAML_DIR})" ]; then + echo "all cwagent-otel-collector configurations have been removed" + rm -f "${YAML}" + else + for file in "${YAML_DIR}"/*; do + base="${YAML_DIR}/$(basename "${file}" .tmp)" if [ "${file}" = "${base}" ]; then rm -f "${file}" else mv -f "${file}" "${base}" + cp -f "${base}" "${YAML}" + echo "cwagent-otel-collector config has been successfully fetched." fi done - elif [ "${multi_config}" = 'append' ]; then - for file in "${JSON_DIR}"/*.tmp; do - mv -f "${file}" "${JSON_DIR}/$(basename "${file}" .tmp)" - done fi if [ "${restart}" = 'true' ]; then - cwa_stop - cwa_start + agent_stop "${CWOC_NAME}" + agent_start "${CWOC_NAME}" "${param_mode}" fi } main() { action='' - config_location='default' + cwa_config_location='' + cwoc_config_location='' restart='false' mode='ec2' @@ -252,60 +453,61 @@ main() { elif [ "$(systemctl | grep -c -E '\-\.mount\s')" = 1 ]; then SYSTEMD='true' elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then - echo "sysv-init is not supported" >&2 - exit 1 + echo "sysv-init is not supported" >&2 + exit 1 else - echo "unknown init system" >&2 - exit 1 + echo "unknown init system" >&2 + exit 1 fi OPTIND=1 - while getopts ":hsa:r:c:m:" opt; do - case "${opt}" in - h) echo "${UsageString}" - exit 0 - ;; - s) restart='true' ;; - a) action="${OPTARG}" ;; - c) config_location="${OPTARG}" ;; - m) mode="${OPTARG}" ;; - \?) echo "Invalid option: -${OPTARG} ${UsageString}" >&2 - ;; - :) echo "Option -${OPTARG} requires an argument ${UsageString}" >&2 - exit 1 - ;; - esac + while getopts ":hsa:c:o:m:" opt; do + case "${opt}" in + h) echo "${UsageString}" + exit 0 + ;; + s) restart='true' ;; + a) action="${OPTARG}" ;; + c) cwa_config_location="${OPTARG}" ;; + o) cwoc_config_location="${OPTARG}" ;; + m) mode="${OPTARG}" ;; + \?) echo "Invalid option: -${OPTARG} ${UsageString}" >&2 + ;; + :) echo "Option -${OPTARG} requires an argument ${UsageString}" >&2 + exit 1 + ;; + esac done - shift "$(( ${OPTIND} - 1 ))" + shift "$(( OPTIND - 1 ))" case "${mode}" in - ec2) - ;; - onPremise) - ;; - auto) - ;; - *) echo "Invalid mode: ${mode} ${UsageString}" >&2 - exit 1 - ;; + ec2) + ;; + onPremise) + ;; + auto) + ;; + *) echo "Invalid mode: ${mode} ${UsageString}" >&2 + exit 1 + ;; esac case "${action}" in - stop) cwa_stop ;; - start) cwa_start "${mode}" ;; - fetch-config) cwa_config "${config_location}" "${restart}" "${mode}" 'default';; - append-config) cwa_config "${config_location}" "${restart}" "${mode}" 'append';; - remove-config) cwa_config "${config_location}" "${restart}" "${mode}" 'remove';; - status) cwa_status ;; + stop) stop_all ;; + start) start_all "${mode}" ;; + fetch-config) config_all "${cwa_config_location}" "${cwoc_config_location}" "${restart}" "${mode}" 'default';; + append-config) config_all "${cwa_config_location}" "${cwoc_config_location}" "${restart}" "${mode}" 'append';; + remove-config) config_all "${cwa_config_location}" "${cwoc_config_location}" "${restart}" "${mode}" 'remove';; + status) status_all ;; # helpers for ssm package scripts to workaround fact that it can't determine if invocation is due to # upgrade or install - prep-restart) cwa_prep_restart ;; - cond-restart) cwa_cond_restart ;; + prep-restart) prep_restart_all ;; + cond-restart) cond_restart_all ;; # helper for rpm+deb uninstallation hooks, not expected to be called manually - preun) cwa_preun ;; - *) echo "Invalid action: ${action} ${UsageString}" >&2 - exit 1 - ;; + preun) preun_all ;; + *) echo "Invalid action: ${action} ${UsageString}" >&2 + exit 1 + ;; esac } diff --git a/packaging/dependencies/cwagent-otel-collector.service b/packaging/dependencies/cwagent-otel-collector.service new file mode 100644 index 0000000000..284a6a6c28 --- /dev/null +++ b/packaging/dependencies/cwagent-otel-collector.service @@ -0,0 +1,22 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT + +# Location: /etc/systemd/system/aws-otel-collector.service +# systemctl enable cwagent-otel-collector +# systemctl start cwagent-otel-collector +# systemctl | grep cwagent-otel-collector +# https://www.freedesktop.org/software/systemd/man/systemd.unit.html + +[Unit] +Description=CWAgent OTel Collector +After=network.target + +[Service] +Type=simple +ExecStart=/opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector --config /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.yaml +KillMode=process +Restart=on-failure +RestartSec=60s + +[Install] +WantedBy=multi-user.target diff --git a/packaging/linux/amazon-cloudwatch-agent.spec b/packaging/linux/amazon-cloudwatch-agent.spec index 311162b927..ad58424c3d 100644 --- a/packaging/linux/amazon-cloudwatch-agent.spec +++ b/packaging/linux/amazon-cloudwatch-agent.spec @@ -2,7 +2,7 @@ Summary: Amazon CloudWatch Agent Name: amazon-cloudwatch-agent Version: %{AGENT_VERSION} Release: 1 -License: MIT License. Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +License: MIT License. Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. Group: Applications/CloudWatch-Agent BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) @@ -30,12 +30,15 @@ ln -f -s /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl ${RPM_ # etc mkdir -p ${RPM_BUILD_ROOT}/etc/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/etc ${RPM_BUILD_ROOT}/etc/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc ${RPM_BUILD_ROOT}/etc/amazon/cwagent-otel-collector # log mkdir -p ${RPM_BUILD_ROOT}/var/log/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/logs ${RPM_BUILD_ROOT}/var/log/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs ${RPM_BUILD_ROOT}/var/log/amazon/cwagent-otel-collector # pid mkdir -p ${RPM_BUILD_ROOT}/var/run/amazon ln -f -s /opt/aws/amazon-cloudwatch-agent/var ${RPM_BUILD_ROOT}/var/run/amazon/amazon-cloudwatch-agent +ln -f -s /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var ${RPM_BUILD_ROOT}/var/run/amazon/cwagent-otel-collector %files %dir /opt/aws @@ -46,6 +49,10 @@ ln -f -s /opt/aws/amazon-cloudwatch-agent/var ${RPM_BUILD_ROOT}/var/run/amazon/a %dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d %dir /opt/aws/amazon-cloudwatch-agent/logs %dir /opt/aws/amazon-cloudwatch-agent/var +%dir /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc +%dir /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.d +%dir %attr(-, cwagent, cwagent) /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/logs +%dir %attr(-, cwagent, cwagent) /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl /opt/aws/amazon-cloudwatch-agent/bin/CWAGENT_VERSION @@ -53,8 +60,10 @@ ln -f -s /opt/aws/amazon-cloudwatch-agent/var ${RPM_BUILD_ROOT}/var/run/amazon/a /opt/aws/amazon-cloudwatch-agent/bin/config-downloader /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard /opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent +/opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector /opt/aws/amazon-cloudwatch-agent/doc/amazon-cloudwatch-agent-schema.json %config(noreplace) /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml +/opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/var/.predefined-config-data /opt/aws/amazon-cloudwatch-agent/LICENSE /opt/aws/amazon-cloudwatch-agent/NOTICE @@ -62,11 +71,16 @@ ln -f -s /opt/aws/amazon-cloudwatch-agent/var ${RPM_BUILD_ROOT}/var/run/amazon/a /opt/aws/amazon-cloudwatch-agent/RELEASE_NOTES /etc/init/amazon-cloudwatch-agent.conf /etc/systemd/system/amazon-cloudwatch-agent.service +/etc/init/cwagent-otel-collector.conf +/etc/systemd/system/cwagent-otel-collector.service /usr/bin/amazon-cloudwatch-agent-ctl /etc/amazon/amazon-cloudwatch-agent /var/log/amazon/amazon-cloudwatch-agent /var/run/amazon/amazon-cloudwatch-agent +/etc/amazon/cwagent-otel-collector +/var/log/amazon/cwagent-otel-collector +/var/run/amazon/cwagent-otel-collector %pre # Stop the agent before upgrades. diff --git a/packaging/linux/cwagent-otel-collector.conf b/packaging/linux/cwagent-otel-collector.conf new file mode 100644 index 0000000000..ba2f182285 --- /dev/null +++ b/packaging/linux/cwagent-otel-collector.conf @@ -0,0 +1,15 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT + +description "CWAgent OTel Collector" +author "Amazon.com" + +start on (runlevel [345] and started network) +stop on (runlevel [!345] or stopping network) + +normal exit 0 + +respawn + +exec /opt/aws/amazon-cloudwatch-agent/bin/cwagent-otel-collector --config /opt/aws/amazon-cloudwatch-agent/cwagent-otel-collector/etc/cwagent-otel-collector.yaml +post-stop exec sleep 1 diff --git a/packaging/windows/amazon-cloudwatch-agent-ctl.ps1 b/packaging/windows/amazon-cloudwatch-agent-ctl.ps1 index 1471336e30..8d605d6fb8 100644 --- a/packaging/windows/amazon-cloudwatch-agent-ctl.ps1 +++ b/packaging/windows/amazon-cloudwatch-agent-ctl.ps1 @@ -1,5 +1,5 @@ -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: MIT +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT Param ( [Parameter(Mandatory = $false)] @@ -7,7 +7,9 @@ Param ( [Parameter(Mandatory = $false)] [switch]$Help, [Parameter(Mandatory = $false)] - [string]$ConfigLocation = 'default', + [string]$ConfigLocation = '', + [Parameter(Mandatory = $false)] + [string]$OtelConfigLocation = '', [Parameter(Mandatory = $false)] [switch]$Start = $false, [Parameter(Mandatory = $false)] @@ -22,7 +24,7 @@ $ErrorActionPreference = "Stop" $UsageString = @" - usage: amazon-cloudwatch-agent-ctl.ps1 -a stop|start|status|fetch-config|append-config|remove-config [-m ec2|onPremise|auto] [-c default|ssm:|file:] [-s] + usage: amazon-cloudwatch-agent-ctl.ps1 -a stop|start|status|fetch-config|append-config|remove-config [-m ec2|onPremise|auto] [-c default|all|ssm:|file:] [-o default|all|ssm: |file:] [-s] e.g. 1. apply a SSM parameter store config on EC2 instance and restart the agent afterwards: @@ -33,31 +35,42 @@ $UsageString = @" amazon-cloudwatch-agent-ctl.ps1 -a status -a: action - stop: stop the agent process. - start: start the agent process. - status: get the status of the agent process. - fetch-config: use this json config as the agent's only configuration. - append-config: append json config with the existing json configs if any. - remove-config: remove json config based on the location (ssm parameter store name, file name) + stop: stop both amazon-cloudwatch-agent and cwagent-otel-collector if running. + start: start both amazon-cloudwatch-agent and cwagent-otel-collector if configuration is available. + status: get the status of both agent processes. + fetch-config: apply config for agent, followed by -c or -o or both. Target config can be based on location (ssm parameter store name, file name), or 'default'. + append-config: append json config with the existing json configs if any, followed by -c. Target config can be based on the location (ssm parameter store name, file name), or 'default'. + remove-config: remove config for agent, followed by -c or -o or both. Target config can be based on the location (ssm parameter store name, file name), or 'all'. -m: mode ec2: indicate this is on ec2 host. onPremise: indicate this is on onPremise host. auto: use ec2 metadata to determine the environment, may not be accurate if ec2 metadata is not available for some reason on EC2. - -c: configuration + -c: amazon-cloudwatch-agent configuration + default: default configuration for quick trial. + ssm:: ssm parameter store name. + file:: file path on the host. + all: all existing configs. Only apply to remove-config action. + + -o: cwagent-otel-collector configuration default: default configuration for quick trial. - ssm:: ssm parameter store name - file:: file path on the host + ssm:: ssm parameter store name. + file:: file path on the host. + all: all existing configs. Only apply to remove-config action. -s: optionally restart after configuring the agent configuration this parameter is used for 'fetch-config', 'append-config', 'remove-config' action only. + "@ $CWAServiceName = 'AmazonCloudWatchAgent' +$CWOCServiceName = 'CWAgentOtelCollector' $CWAServiceDisplayName = 'Amazon CloudWatch Agent' +$CWOCServiceDisplayName = 'CWAgent Otel Collector' $CWADirectory = 'Amazon\AmazonCloudWatchAgent' +$AllConfig = 'all' $CWAProgramFiles = "${Env:ProgramFiles}\${CWADirectory}" if ($Env:ProgramData) { @@ -69,7 +82,8 @@ if ($Env:ProgramData) { $CWALogDirectory = "${CWAProgramData}\Logs" -$RestartFile ="${CWAProgramData}\restart" +$CWARestartFile ="${CWAProgramData}\restart" +$CWOCRestartFile ="${CWAProgramData}\cwoc-restart" $VersionFile ="${CWAProgramFiles}\CWAGENT_VERSION" $CVLogFile="${CWALogDirectory}\configuration-validation.log" @@ -77,96 +91,209 @@ $CVLogFile="${CWALogDirectory}\configuration-validation.log" $TOML="${CWAProgramData}\amazon-cloudwatch-agent.toml" $JSON="${CWAProgramData}\amazon-cloudwatch-agent.json" $JSON_DIR = "${CWAProgramData}\Configs" +$YAML="${CWAProgramData}\${CWOCServiceName}\cwagent-otel-collector.yaml" +$YAML_DIR="${CWAProgramData}\${CWOCServiceName}\Configs" +$PREDEFINED_CONFIG_DATA="${CWAProgramData}\${CWOCServiceName}\predefined-config-data" $COMMON_CONIG="${CWAProgramData}\common-config.toml" $EC2 = $false # WMI is unavailable on Nano, CIM is unavailable on 2003 $CIM = $false -Function CWAStart() { - if (!(Test-Path -LiteralPath "${TOML}")) { - Write-Output "amazon-cloudwatch-agent is not configured. Applying default configuration before starting it." - CWAConfig +Function StartAll() { + Write-Output "****** processing cwagent-otel-collector ******" + AgentStart -service_name $CWOCServiceName -service_display_name $CWOCServiceDisplayName + + Write-Output "`r`n****** processing amazon-cloudwatch-agent ******" + AgentStart -service_name $CWAServiceName -service_display_name $CWAServiceDisplayName +} + +Function AgentStart() { + Param ( + [Parameter(Mandatory = $true)] + [string]$service_name, + [Parameter(Mandatory = $true)] + [string]$service_display_name + ) + + if (${service_name} -eq $CWOCServiceName -And !(Test-Path -LiteralPath "${YAML}")) { + Write-Output "cwagent-otel-collector will not be started as it has not been configured yet." + return + } + + if (${service_name} -eq $CWAServiceName -And !(Test-Path -LiteralPath "${TOML}")) { + # If cwagent-otel-collector config exists, amazon-cloudwatch-agent default config will be suppressed + if (Test-Path -LiteralPath "${YAML}") { + Write-Output "amazon-cloudwatch-agent will not be started as it has not been configured yet." + return + } + Write-Output "Both amazon-cloudwatch-agent and cwagent-otel-collector are not configured. Applying amazon-cloudwatch-agent default configuration." + $ConfigLocation = 'default' + CWAConfig -multi_config 'default' } - $svc = Get-Service -Name "${CWAServiceName}" -ErrorAction SilentlyContinue + + $svc = Get-Service -Name "${service_name}" -ErrorAction SilentlyContinue if (!$svc) { - New-Service -Name "${CWAServiceName}" -DisplayName "${CWAServiceDisplayName}" -Description "${CWAServiceDisplayName}" -DependsOn LanmanServer -BinaryPathName "`"${CWAProgramFiles}\start-amazon-cloudwatch-agent.exe`"" | Out-Null + $startCommand = "`"${CWAProgramFiles}\start-amazon-cloudwatch-agent.exe`"" + if (${service_name} -eq $CWOCServiceName) { + $startCommand = "`"${CWAProgramFiles}\cwagent-otel-collector.exe`" --config=${YAML}" + } + New-Service -Name "${service_name}" -DisplayName "${service_display_name}" -Description "${service_display_name}" -DependsOn LanmanServer -BinaryPathName "${startCommand}" | Out-Null # object returned by New-Service gives errors so retrieve it again - $svc = Get-Service -Name "${CWAServiceName}" + $svc = Get-Service -Name "${service_name}" # Configure the service to restart on crashes. It's unclear how to do this through WMI or CIM interface so using sc.exe # Restarts immediately on the first two crashes then gives a 2 second sleep after any subsequent crash. - & sc.exe failure "${CWAServiceName}" reset= 86400 actions= restart/0/restart/0/restart/2000 | Out-Null + & sc.exe failure "${service_name}" reset= 86400 actions= restart/0/restart/0/restart/2000 | Out-Null if ($CIM) { - & sc.exe failureflag "${CWAServiceName}" 1 | Out-Null + & sc.exe failureflag "${service_name}" 1 | Out-Null } } $svc | Start-Service + Write-Output "$service_name has been started" +} + +Function StopAll() { + Write-Output "****** processing cwagent-otel-collector ******" + AgentStop -service_name $CWOCServiceName + + Write-Output "`r`n****** processing amazon-cloudwatch-agent ******" + AgentStop -service_name $CWAServiceName } -Function CWAStop() { - $svc = Get-Service -Name "${CWAServiceName}" -ErrorAction SilentlyContinue +Function AgentStop() { + Param ( + [Parameter(Mandatory = $true)] + [string]$service_name + ) + $svc = Get-Service -Name "${service_name}" -ErrorAction SilentlyContinue if ($svc) { $svc | Stop-Service } + Write-Output "$service_name has been stopped" } -Function CWAPrepRestart() { - if ((CWARunstatus) -eq 'running') { - Write-Output $null > $RestartFile +Function PrepRestartAll() { + AgentPrepRestart -service_name $CWOCServiceName -restart_file $CWOCRestartFile + AgentPrepRestart -service_name $CWAServiceName -restart_file $CWARestartFile +} + +Function AgentPrepRestart() { + Param ( + [Parameter(Mandatory = $true)] + [string]$restart_file, + [Parameter(Mandatory = $true)] + [string]$service_name + ) + if ((Runstatus -service_name $service_name) -eq 'running') { + Write-Output $null > $restart_file } } -Function CWACondRestart() { - if (Test-Path -LiteralPath "${RestartFile}") { - CWAStart - Remove-Item -LiteralPath "${RestartFile}" +Function CondRestartAll() { + AgentCondRestart -service_name $CWOCServiceName -service_display_name $CWOCServiceDisplayName -restart_file $CWOCRestartFile + AgentCondRestart -service_name $CWAServiceName -service_display_name $CWAServiceDisplayName -restart_file $CWARestartFile +} + +Function AgentCondRestart() { + Param ( + [Parameter(Mandatory = $true)] + [string]$restart_file, + [Parameter(Mandatory = $true)] + [string]$service_name, + [Parameter(Mandatory = $true)] + [string]$service_display_name + ) + if (Test-Path -LiteralPath "${restart_file}") { + AgentStart -service_name $service_name -service_display_name $service_display_name + Remove-Item -LiteralPath "${restart_file}" } } -Function CWAPreun() { - CWAStop +Function PreunAll() { + AgentPreun -service_name $CWOCServiceName + AgentPreun -service_name $CWAServiceName +} + +Function AgentPreun() { + Param ( + [Parameter(Mandatory = $true)] + [string]$service_name + ) + + AgentStop -service_name $service_name if ($CIM) { - $svc = Get-CimInstance -ClassName Win32_Service -Filter "name='${CWAServiceName}'" + $svc = Get-CimInstance -ClassName Win32_Service -Filter "name='${service_name}'" $svc | Invoke-CimMethod -MethodName 'delete' | Out-Null } else { - $svc = Get-WmiObject -Class Win32_Service -Filter "name='${CWAServiceName}'" + $svc = Get-WmiObject -Class Win32_Service -Filter "name='${service_name}'" $svc.delete() | Out-Null } } -Function CWAStatus() { +Function StatusAll() { + + $cwa_status = Runstatus -service_name ${CWAServiceName} + $cwa_starttime = GetStarttime -service_name ${CWAServiceName} + $cwa_config_status = 'configured' + if (!(Test-Path -LiteralPath "${TOML}")) { + $cwa_config_status = 'not configured' + } + + $cwoc_status = Runstatus -service_name ${CWOCServiceName} + $cwoc_starttime = GetStarttime -service_name ${CWOCServiceName} + $cwoc_config_status = 'configured' + if (!(Test-Path -LiteralPath "${YAML}")) { + $cwoc_config_status = 'not configured' + } + + $version = ([IO.File]::ReadAllText("${VersionFile}")).Trim() + + Write-Output "{" + Write-Output " `"status`": `"${cwa_status}`"," + Write-Output " `"starttime`": `"${cwa_starttime}`"," + Write-Output " `"configstatus`": `"${cwa_config_status}`"," + Write-Output " `"cwoc_status`": `"${cwoc_status}`"," + Write-Output " `"cwoc_starttime`": `"${cwoc_starttime}`"," + Write-Output " `"cwoc_configstatus`": `"${cwoc_config_status}`"," + Write-Output " `"version`": `"${version}`"" + Write-Output "}" +} + +Function GetStarttime() { + Param ( + [Parameter(Mandatory = $true)] + [string]$service_name + ) $timefmt='' if ($CIM) { - $svc = Get-CimInstance -ClassName Win32_Service -Filter "name='${CWAServiceName}'" + $svc = Get-CimInstance -ClassName Win32_Service -Filter "name='${service_name}'" } else { - $svc = Get-WmiObject -Class Win32_Service -Filter "name='${CWAServiceName}'" + $svc = Get-WmiObject -Class Win32_Service -Filter "name='${service_name}'" } if ($svc) { - $cwapid = $svc.ProcessId - $process = Get-Process -Id "${cwapid}" + $agentPid = $svc.ProcessId + $process = Get-Process -Id "${agentPid}" $processStart = $process.StartTime if ($processStart) { $timefmt = Get-Date -Date ${processStart} -Format "s" } } - - $status = CWARunstatus - $version = ([IO.File]::ReadAllText("${VersionFile}")).Trim() - - Write-Output "{" - Write-Output " `"status`": `"${status}`"," - Write-Output " `"starttime`": `"${timefmt}`"," - Write-Output " `"version`": `"${version}`"" - Write-Output "}" + + return $timefmt } # Translate platform status names to those used across all CWAgent's platforms -Function CWARunstatus() { +Function Runstatus() { + Param ( + [Parameter(Mandatory = $true)] + [string]$service_name + ) + $running = $false - $svc = Get-Service -Name "${CWAServiceName}" -ErrorAction SilentlyContinue + $svc = Get-Service -Name "${service_name}" -ErrorAction SilentlyContinue if ($svc -and ($svc.Status -eq 'running')) { $running = $true } @@ -177,6 +304,26 @@ Function CWARunstatus() { } } +Function ConfigAll() { + Param ( + [Parameter(Mandatory = $false)] + [string]$multi_config = 'default' + ) + + if ($OtelConfigLocation) { + Write-Output "****** processing cwagent-otel-collector ******" + CWOCConfig -multi_config ${multi_config} + Write-Output "" + } + + # cwa_config is called after cwoc_config becuase that whether applying + # default cwa config depends on the existence of cwoc config + if ($ConfigLocation) { + Write-Output "****** processing amazon-cloudwatch-agent ******" + CWAConfig -multi_config ${multi_config} + } +} + Function CWAConfig() { Param ( [Parameter(Mandatory = $false)] @@ -188,49 +335,127 @@ Function CWAConfig() { $param_mode="onPrem" } - & $CWAProgramFiles\config-downloader.exe --output-dir "${JSON_DIR}" --download-source "${ConfigLocation}" --mode "${param_mode}" --config "${COMMON_CONIG}" --multi-config "${multi_config}" - CheckCMDResult - Write-Output "Start configuration validation..." - & cmd /c "`"$CWAProgramFiles\config-translator.exe`" --input ${JSON} --input-dir ${JSON_DIR} --output ${TOML} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config} 2>&1" - CheckCMDResult - # Let command pass so we can check return code and give user-friendly error-message - $ErrorActionPreference = "Continue" - & cmd /c "`"${CWAProgramFiles}\amazon-cloudwatch-agent.exe`" --schematest --config ${TOML} 2>&1" | Out-File $CVLogFile - if ($LASTEXITCODE -ne 0) { - Write-Output "Configuration validation second phase failed" - Write-Output "======== Error Log ========" - cat $CVLogFile - exit 1 + if ($ConfigLocation -eq $AllConfig -And $multi_config -ne 'remove') { + Write-Output "ignore cwa configuration `"$AllConfig`" as it is only supported by action `"remove-config`"" + return + } + + if ($ConfigLocation -eq $AllConfig) { + Remove-Item -Path "${JSON_DIR}\*" -Force -ErrorAction SilentlyContinue + } else { + & $CWAProgramFiles\config-downloader.exe --output-dir "${JSON_DIR}" --download-source "${ConfigLocation}" --mode "${param_mode}" --config "${COMMON_CONIG}" --multi-config "${multi_config}" + CheckCMDResult + } + + $jsonDirContent = Get-ChildItem "${JSON_DIR}" | Measure-Object + + if ($jsonDirContent.count -eq 0) { + Write-Output "all amazon-cloudwatch-agent configurations have been removed" + Remove-Item "${TOML}" -Force -ErrorAction SilentlyContinue + } else { + Write-Output "Start configuration validation..." + & cmd /c "`"$CWAProgramFiles\config-translator.exe`" --input ${JSON} --input-dir ${JSON_DIR} --output ${TOML} --mode ${param_mode} --config ${COMMON_CONIG} --multi-config ${multi_config} 2>&1" + CheckCMDResult + # Let command pass so we can check return code and give user-friendly error-message + $ErrorActionPreference = "Continue" + & cmd /c "`"${CWAProgramFiles}\amazon-cloudwatch-agent.exe`" --schematest --config ${TOML} 2>&1" | Out-File $CVLogFile + if ($LASTEXITCODE -ne 0) { + Write-Output "Configuration validation second phase failed" + Write-Output "======== Error Log ========" + cat $CVLogFile + exit 1 + } else { + Write-Output "Configuration validation second phase succeeded" + } + $ErrorActionPreference = "Stop" + Write-Output "Configuration validation succeeded" + + # for translator: + # default: only process .tmp files + # append: process both existing files and .tmp files + # remove: only process existing files + # At this point, all json configs have been validated + # multi_config: + # default: delete non .tmp file, rename .tmp file + # append: rename .tmp file + # remove: no-op + if ($multi_config -eq 'default') { + Remove-Item "${JSON}" -Force -ErrorAction SilentlyContinue + Remove-Item -Path "${JSON_DIR}\*" -Exclude "*.tmp" -Force -ErrorAction SilentlyContinue + Get-ChildItem "${JSON_DIR}\*.tmp" | Rename-Item -NewName { $_.name -Replace '\.tmp$','' } + } elseif ($multi_config -eq 'append') { + Get-ChildItem "${JSON_DIR}\*.tmp" | ForEach-Object { + $newName = $_.name -Replace '\.tmp$','' + $destination = Join-Path -Path $_.Directory.FullName -ChildPath "${newName}" + Move-Item -Path $_.FullName -Destination "${destination}" -Force + } + } + } + + if ($Start) { + AgentStop -service_name $CWAServiceName + AgentStart -service_name $CWAServiceName -service_display_name $CWAServiceDisplayName + } +} + +Function CWOCConfig() { + Param ( + [Parameter(Mandatory = $false)] + [string]$multi_config = 'default' + ) + + if (Test-Path -LiteralPath "${Env:ProgramFiles}\Amazon\AWSOTelCollector\aws-otel-collector-ctl.ps1") { + Write-Output "REMINDER: you are configuring `"cwagent-otel-collector`" instead of `"aws-otel-collector`"." + } + + if ($multi_config -eq 'append') { + Write-Output "ignore `"-o`" as cwagent-otel-collector doesn't support append-config" + return + } + + $param_mode="ec2" + if (!$EC2) { + $param_mode="onPrem" + } + + if ($OtelConfigLocation -eq $AllConfig -And $multi_config -ne 'remove') { + Write-Output "ignore cwoc configuration `"$AllConfig`" as it is only supported by action `"remove-config`"" + return + } + + if ($OtelConfigLocation -eq $AllConfig) { + Remove-Item -Path "${YAML_DIR}\*" -Force -ErrorAction SilentlyContinue + } elseif ($multi_config -eq 'default' -And $OtelConfigLocation -eq 'default') { + Copy-Item "${PREDEFINED_CONFIG_DATA}" -Destination "${YAML_DIR}/default.tmp" + Write-Output "Successfully fetched the config and saved in ${YAML_DIR}\default.tmp" } else { - Write-Output "Configuration validation second phase succeeded" - } - $ErrorActionPreference = "Stop" - Write-Output "Configuration validation succeeded" - - # for translator: - # default: only process .tmp files - # append: process both existing files and .tmp files - # remove: only process existing files - # At this point, all json configs have been validated - # multi_config: - # default: delete non .tmp file, rename .tmp file - # append: rename .tmp file - # remove: no-op - if ($multi_config -eq 'default') { - Remove-Item "${JSON}" -Force -ErrorAction SilentlyContinue - Remove-Item -Path "${JSON_DIR}\*" -Exclude "*.tmp" -Force -ErrorAction SilentlyContinue - Get-ChildItem "${JSON_DIR}\*.tmp" | Rename-Item -NewName { $_.name -Replace '\.tmp$','' } - } elseif ($multi_config -eq 'append') { - Get-ChildItem "${JSON_DIR}\*.tmp" | ForEach-Object { + & $CWAProgramFiles\config-downloader.exe --output-dir "${YAML_DIR}" --download-source "${OtelConfigLocation}" --mode "${param_mode}" --config "${COMMON_CONIG}" --multi-config "${multi_config}" + if ($LASTEXITCODE -ne 0) { + return + } + } + + $yamlDirContent = Get-ChildItem "${YAML_DIR}" | Measure-Object + if ($yamlDirContent.count -eq 0) { + Write-Output "all cwagent-otel-collector configurations have been removed" + Remove-Item "${YAML}" -Force -ErrorAction SilentlyContinue + } else { + # delete old file which are without .tmp suffix + Remove-Item -Path "${YAML_DIR}\*" -Exclude "*.tmp" -Force -ErrorAction SilentlyContinue + + # trip the .tmp suffix from new file, and copy it to the YAML + Get-ChildItem "${YAML_DIR}" | ForEach-Object { $newName = $_.name -Replace '\.tmp$','' $destination = Join-Path -Path $_.Directory.FullName -ChildPath "${newName}" - Move-Item -Path $_.FullName -Destination "${destination}" -Force + Move-Item $_.FullName -Destination "${destination}" -Force + Copy-Item "${destination}" -Destination "${YAML}" -Force + Write-Output "cwagent-otel-collector config has been successfully fetched." } } if ($Start) { - CWAStop - CWAStart + AgentStop -service_name $CWOCServiceName + AgentStart -service_name $CWOCServiceName -service_display_name $CWOCServiceDisplayName } } @@ -247,7 +472,6 @@ Function CheckCMDResult($ErrorMessag, $SucessMessage) { Write-Output $SucessMessage } } - } # TODO Occasionally metadata service isn't available and this gives a false negative - might @@ -293,15 +517,15 @@ Function main() { } switch -exact ($Action) { - stop { CWAStop } - start { CWAStart } - fetch-config { CWAConfig } - append-config { CWAConfig -multi_config 'append' } - remove-config { CWAConfig -multi_config 'remove' } - status { CWAStatus } - prep-restart { CWAPrepRestart } - cond-restart { CWACondRestart } - preun { CWAPreun } + stop { StopAll } + start { StartAll } + fetch-config { ConfigAll } + append-config { ConfigAll -multi_config 'append' } + remove-config { ConfigAll -multi_config 'remove' } + status { StatusAll } + prep-restart { PrepRestartAll } + cond-restart { CondRestartAll } + preun { PreunAll } default { Write-Output "Invalid action: ${Action}`n${UsageString}" Exit 1 diff --git a/packaging/windows/install.ps1 b/packaging/windows/install.ps1 index be7b1cc575..9aa7e1c37b 100644 --- a/packaging/windows/install.ps1 +++ b/packaging/windows/install.ps1 @@ -5,12 +5,17 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" $CWADirectory = 'Amazon\AmazonCloudWatchAgent' +$CWOCDirectory = 'Amazon\AmazonCloudWatchAgent\CWAgentOtelCollector' + $CWAProgramFiles = "${Env:ProgramFiles}\${CWADirectory}" + if ($Env:ProgramData) { $CWAProgramData = "${Env:ProgramData}\${CWADirectory}" + $CWOCProgramData = "${Env:ProgramData}\${CWOCDirectory}" } else { # Windows 2003 $CWAProgramData = "${Env:ALLUSERSPROFILE}\Application Data\${CWADirectory}" + $CWOCProgramData = "${Env:ALLUSERSPROFILE}\Application Data\${CWOCDirectory}" } $Cmd = "${CWAProgramFiles}\amazon-cloudwatch-agent-ctl.ps1" @@ -18,6 +23,8 @@ $Cmd = "${CWAProgramFiles}\amazon-cloudwatch-agent-ctl.ps1" New-Item -ItemType Directory -Force -Path "${CWAProgramFiles}" | Out-Null New-Item -ItemType Directory -Force -Path "${CWAProgramData}\Logs" | Out-Null New-Item -ItemType Directory -Force -Path "${CWAProgramData}\Configs" | Out-Null +New-Item -ItemType Directory -Force -Path "${CWOCProgramData}\Logs" | Out-Null +New-Item -ItemType Directory -Force -Path "${CWOCProgramData}\Configs" | Out-Null @( "LICENSE", @@ -31,6 +38,7 @@ New-Item -ItemType Directory -Force -Path "${CWAProgramData}\Configs" | Out-Null "config-translator.exe", "amazon-cloudwatch-agent-config-wizard.exe", "amazon-cloudwatch-agent-schema.json" +"cwagent-otel-collector.exe" ) | ForEach-Object { Copy-Item ".\$_" -Destination "${CWAProgramFiles}" -Force } @@ -38,4 +46,8 @@ New-Item -ItemType Directory -Force -Path "${CWAProgramData}\Configs" | Out-Null "common-config.toml" ) | ForEach-Object { Copy-Item ".\$_" -Destination "${CWAProgramData}" -Force } +@( +"predefined-config-data" +) | ForEach-Object { Copy-Item ".\$_" -Destination "${CWOCProgramData}" -Force } + & "${Cmd}" -Action cond-restart