From 26d1152c8f321c2baaad02d4df3c76b75805166a Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 7 Mar 2025 13:02:59 -0500 Subject: [PATCH 01/22] Update repo IA --- .gitignore | 21 ++++++++++++++----- .../go/19March2025GoRootTest.go | 0 ...ann-basic-with-scenario.snippet.example.go | 0 .../go/ann-basic.snippet.example.go | 0 ...nn-filter-with-scenario.snippet.example.go | 0 .../go/ann-filter.snippet.example.go | 0 .../go/create-index-basic.snippet.example.go | 0 .../go/create-index-filter.snippet.example.go | 0 ...-filter-using-scenarios.snippet.example.go | 0 .../go/deletemeplease.go | 0 .../go/drop-index.snippet.example.go | 0 .../go/edit-index.snippet.example.go | 0 .../go/enn.snippet.example.go | 0 .../go/v2/19marchtestv2Folder.go | 0 .../go/view-index.snippet.example.go | 0 .../java/AnnQueryBasic.snippet.example.java | 0 .../java/AnnQueryFilter.snippet.example.java | 0 .../CreateIndexBasic.snippet.example.java | 0 .../CreateIndexFilter.snippet.example.java | 0 .../java/DropIndex.snippet.example.java | 0 .../java/ViewIndex.snippet.example.java | 0 .../ann-query-basic.snippet.example.js | 0 .../ann-query-filter.snippet.example.js | 0 .../create-index-basic.snippet.example.js | 0 .../create-index-filter.snippet.example.js | 0 .../javascript/drop-index.snippet.example.js | 0 .../javascript/view-index.snippet.example.js | 0 .../python/ann_basic.snippet.example.py | 0 .../python/ann_filter.snippet.example.py | 0 .../python/create_basic.snippet.example.py | 0 .../python/create_filter.snippet.example.py | 0 .../python/drop.snippet.example.py | 0 .../python/langchain.snippet.example.py | 0 .../python/view.snippet.example.py | 0 {go => usage-examples/go/driver}/README.md | 0 {go => usage-examples/go/driver}/bluehawk.sh | 0 .../manage-indexes/IndexDefinition.go | 0 .../manage-indexes/IndexExpectation.go | 0 .../manage-indexes/create-index-basic.go | 0 .../manage-indexes/create-index-filter.go | 0 .../examples/manage-indexes/drop-index.go | 0 .../examples/manage-indexes/edit-index.go | 0 .../manage-indexes/verify-index-definition.go | 0 .../examples/manage-indexes/view-index.go | 0 .../driver}/examples/run-queries/ann-basic.go | 0 .../examples/run-queries/ann-filter.go | 0 .../go/driver}/examples/run-queries/enn.go | 0 {go => usage-examples/go/driver}/go.mod | 0 {go => usage-examples/go/driver}/go.sum | 0 .../go/driver}/newgotestfile.go | 0 .../go/driver}/ohhai_detete_me | 0 .../manage-indexes/manage-indexes_test.go | 0 .../run-queries/VerifyMovieQueryOutput.go | 0 .../VerifyMovieQueryOutputWithFilter.go | 0 .../tests/run-queries/run-queries_test.go | 0 .../go/driver}/v22testfile2.go | 0 {java => usage-examples/java/sync}/README.md | 0 .../java/sync}/bluehawk.sh | 0 {java => usage-examples/java/sync}/pom.xml | 0 .../main/java/indexes/CreateIndexBasic.java | 0 .../main/java/indexes/CreateIndexFilter.java | 0 .../src/main/java/indexes/DropIndex.java | 0 .../src/main/java/indexes/ViewIndex.java | 0 .../src/main/java/queries/AnnQueryBasic.java | 0 .../src/main/java/queries/AnnQueryFilter.java | 0 .../test/java/indexes/ManageIndexesTests.java | 0 .../test/java/indexes/models/Definition.java | 0 .../indexes/models/DefinitionVersion.java | 0 .../src/test/java/indexes/models/Field.java | 0 .../java/indexes/models/IndexDefinition.java | 0 .../test/java/indexes/models/MainIndex.java | 0 .../test/java/indexes/models/MongoDate.java | 0 .../java/indexes/models/StatusDetail.java | 0 .../src/test/java/queries/QueryTests.java | 0 .../javascript}/README.md | 0 .../javascript}/babel.config.cjs | 0 .../javascript}/bluehawk.sh | 0 .../examples/indexes/create-index-basic.js | 0 .../examples/indexes/create-index-filter.js | 0 .../examples/indexes/drop-index.js | 0 .../examples/indexes/view-index.js | 0 .../examples/queries/ann-query-basic.js | 0 .../examples/queries/ann-query-filter.js | 0 .../javascript}/jest.config.cjs | 0 .../javascript}/package-lock.json | 0 .../javascript}/package.json | 0 .../javascript}/tests/manage-indexes.test.js | 0 .../javascript}/tests/run-queries.test.js | 0 {python => usage-examples/python}/README.md | 0 {python => usage-examples/python}/bluehawk.sh | 0 .../python}/examples/indexes/create_basic.py | 0 .../python}/examples/indexes/create_filter.py | 0 .../python}/examples/indexes/drop.py | 0 .../python}/examples/indexes/view.py | 0 .../python}/examples/integration/langchain.py | 0 .../python}/examples/queries/ann_basic.py | 0 .../python}/examples/queries/ann_filter.py | 0 .../tests_package/test_manage_indexes.py | 0 .../python}/tests_package/test_queries.py | 0 99 files changed, 16 insertions(+), 5 deletions(-) rename {generated-examples => generated-usage-examples}/go/19March2025GoRootTest.go (100%) rename {generated-examples => generated-usage-examples}/go/ann-basic-with-scenario.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/ann-basic.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/ann-filter-with-scenario.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/ann-filter.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/create-index-basic.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/create-index-filter.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/create-index-without-filter-using-scenarios.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/deletemeplease.go (100%) rename {generated-examples => generated-usage-examples}/go/drop-index.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/edit-index.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/enn.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/go/v2/19marchtestv2Folder.go (100%) rename {generated-examples => generated-usage-examples}/go/view-index.snippet.example.go (100%) rename {generated-examples => generated-usage-examples}/java/AnnQueryBasic.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/java/AnnQueryFilter.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/java/CreateIndexBasic.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/java/CreateIndexFilter.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/java/DropIndex.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/java/ViewIndex.snippet.example.java (100%) rename {generated-examples => generated-usage-examples}/javascript/ann-query-basic.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/javascript/ann-query-filter.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/javascript/create-index-basic.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/javascript/create-index-filter.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/javascript/drop-index.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/javascript/view-index.snippet.example.js (100%) rename {generated-examples => generated-usage-examples}/python/ann_basic.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/ann_filter.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/create_basic.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/create_filter.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/drop.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/langchain.snippet.example.py (100%) rename {generated-examples => generated-usage-examples}/python/view.snippet.example.py (100%) rename {go => usage-examples/go/driver}/README.md (100%) rename {go => usage-examples/go/driver}/bluehawk.sh (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/IndexDefinition.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/IndexExpectation.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/create-index-basic.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/create-index-filter.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/drop-index.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/edit-index.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/verify-index-definition.go (100%) rename {go => usage-examples/go/driver}/examples/manage-indexes/view-index.go (100%) rename {go => usage-examples/go/driver}/examples/run-queries/ann-basic.go (100%) rename {go => usage-examples/go/driver}/examples/run-queries/ann-filter.go (100%) rename {go => usage-examples/go/driver}/examples/run-queries/enn.go (100%) rename {go => usage-examples/go/driver}/go.mod (100%) rename {go => usage-examples/go/driver}/go.sum (100%) rename {go => usage-examples/go/driver}/newgotestfile.go (100%) rename {go => usage-examples/go/driver}/ohhai_detete_me (100%) rename {go => usage-examples/go/driver}/tests/manage-indexes/manage-indexes_test.go (100%) rename {go => usage-examples/go/driver}/tests/run-queries/VerifyMovieQueryOutput.go (100%) rename {go => usage-examples/go/driver}/tests/run-queries/VerifyMovieQueryOutputWithFilter.go (100%) rename {go => usage-examples/go/driver}/tests/run-queries/run-queries_test.go (100%) rename {go => usage-examples/go/driver}/v22testfile2.go (100%) rename {java => usage-examples/java/sync}/README.md (100%) rename {java => usage-examples/java/sync}/bluehawk.sh (100%) rename {java => usage-examples/java/sync}/pom.xml (100%) rename {java => usage-examples/java/sync}/src/main/java/indexes/CreateIndexBasic.java (100%) rename {java => usage-examples/java/sync}/src/main/java/indexes/CreateIndexFilter.java (100%) rename {java => usage-examples/java/sync}/src/main/java/indexes/DropIndex.java (100%) rename {java => usage-examples/java/sync}/src/main/java/indexes/ViewIndex.java (100%) rename {java => usage-examples/java/sync}/src/main/java/queries/AnnQueryBasic.java (100%) rename {java => usage-examples/java/sync}/src/main/java/queries/AnnQueryFilter.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/ManageIndexesTests.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/Definition.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/DefinitionVersion.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/Field.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/IndexDefinition.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/MainIndex.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/MongoDate.java (100%) rename {java => usage-examples/java/sync}/src/test/java/indexes/models/StatusDetail.java (100%) rename {java => usage-examples/java/sync}/src/test/java/queries/QueryTests.java (100%) rename {javascript => usage-examples/javascript}/README.md (100%) rename {javascript => usage-examples/javascript}/babel.config.cjs (100%) rename {javascript => usage-examples/javascript}/bluehawk.sh (100%) rename {javascript => usage-examples/javascript}/examples/indexes/create-index-basic.js (100%) rename {javascript => usage-examples/javascript}/examples/indexes/create-index-filter.js (100%) rename {javascript => usage-examples/javascript}/examples/indexes/drop-index.js (100%) rename {javascript => usage-examples/javascript}/examples/indexes/view-index.js (100%) rename {javascript => usage-examples/javascript}/examples/queries/ann-query-basic.js (100%) rename {javascript => usage-examples/javascript}/examples/queries/ann-query-filter.js (100%) rename {javascript => usage-examples/javascript}/jest.config.cjs (100%) rename {javascript => usage-examples/javascript}/package-lock.json (100%) rename {javascript => usage-examples/javascript}/package.json (100%) rename {javascript => usage-examples/javascript}/tests/manage-indexes.test.js (100%) rename {javascript => usage-examples/javascript}/tests/run-queries.test.js (100%) rename {python => usage-examples/python}/README.md (100%) rename {python => usage-examples/python}/bluehawk.sh (100%) rename {python => usage-examples/python}/examples/indexes/create_basic.py (100%) rename {python => usage-examples/python}/examples/indexes/create_filter.py (100%) rename {python => usage-examples/python}/examples/indexes/drop.py (100%) rename {python => usage-examples/python}/examples/indexes/view.py (100%) rename {python => usage-examples/python}/examples/integration/langchain.py (100%) rename {python => usage-examples/python}/examples/queries/ann_basic.py (100%) rename {python => usage-examples/python}/examples/queries/ann_filter.py (100%) rename {python => usage-examples/python}/tests_package/test_manage_indexes.py (100%) rename {python => usage-examples/python}/tests_package/test_queries.py (100%) diff --git a/.gitignore b/.gitignore index de5dfbd..d5149dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,23 @@ # MacOS Build Artifacts *.DS_Store -# Don't commit .env files with secret info, EVER + +# Secrets and keys ****DO NOT COMMIT SECRETS*** *.env -# JetBrains IDE files +*/secrets.json + +# Logs +*.log + +# IDE files +## Visual Studio Code files +.vscode +## JetBrains IDE files *.idea -# Python virtual environment +## Python virtual environment */venv -# Node.js dependencies + +# Language specific output +## Node.js dependencies */node_modules -# Java build files +## Java build files */target \ No newline at end of file diff --git a/generated-examples/go/19March2025GoRootTest.go b/generated-usage-examples/go/19March2025GoRootTest.go similarity index 100% rename from generated-examples/go/19March2025GoRootTest.go rename to generated-usage-examples/go/19March2025GoRootTest.go diff --git a/generated-examples/go/ann-basic-with-scenario.snippet.example.go b/generated-usage-examples/go/ann-basic-with-scenario.snippet.example.go similarity index 100% rename from generated-examples/go/ann-basic-with-scenario.snippet.example.go rename to generated-usage-examples/go/ann-basic-with-scenario.snippet.example.go diff --git a/generated-examples/go/ann-basic.snippet.example.go b/generated-usage-examples/go/ann-basic.snippet.example.go similarity index 100% rename from generated-examples/go/ann-basic.snippet.example.go rename to generated-usage-examples/go/ann-basic.snippet.example.go diff --git a/generated-examples/go/ann-filter-with-scenario.snippet.example.go b/generated-usage-examples/go/ann-filter-with-scenario.snippet.example.go similarity index 100% rename from generated-examples/go/ann-filter-with-scenario.snippet.example.go rename to generated-usage-examples/go/ann-filter-with-scenario.snippet.example.go diff --git a/generated-examples/go/ann-filter.snippet.example.go b/generated-usage-examples/go/ann-filter.snippet.example.go similarity index 100% rename from generated-examples/go/ann-filter.snippet.example.go rename to generated-usage-examples/go/ann-filter.snippet.example.go diff --git a/generated-examples/go/create-index-basic.snippet.example.go b/generated-usage-examples/go/create-index-basic.snippet.example.go similarity index 100% rename from generated-examples/go/create-index-basic.snippet.example.go rename to generated-usage-examples/go/create-index-basic.snippet.example.go diff --git a/generated-examples/go/create-index-filter.snippet.example.go b/generated-usage-examples/go/create-index-filter.snippet.example.go similarity index 100% rename from generated-examples/go/create-index-filter.snippet.example.go rename to generated-usage-examples/go/create-index-filter.snippet.example.go diff --git a/generated-examples/go/create-index-without-filter-using-scenarios.snippet.example.go b/generated-usage-examples/go/create-index-without-filter-using-scenarios.snippet.example.go similarity index 100% rename from generated-examples/go/create-index-without-filter-using-scenarios.snippet.example.go rename to generated-usage-examples/go/create-index-without-filter-using-scenarios.snippet.example.go diff --git a/generated-examples/go/deletemeplease.go b/generated-usage-examples/go/deletemeplease.go similarity index 100% rename from generated-examples/go/deletemeplease.go rename to generated-usage-examples/go/deletemeplease.go diff --git a/generated-examples/go/drop-index.snippet.example.go b/generated-usage-examples/go/drop-index.snippet.example.go similarity index 100% rename from generated-examples/go/drop-index.snippet.example.go rename to generated-usage-examples/go/drop-index.snippet.example.go diff --git a/generated-examples/go/edit-index.snippet.example.go b/generated-usage-examples/go/edit-index.snippet.example.go similarity index 100% rename from generated-examples/go/edit-index.snippet.example.go rename to generated-usage-examples/go/edit-index.snippet.example.go diff --git a/generated-examples/go/enn.snippet.example.go b/generated-usage-examples/go/enn.snippet.example.go similarity index 100% rename from generated-examples/go/enn.snippet.example.go rename to generated-usage-examples/go/enn.snippet.example.go diff --git a/generated-examples/go/v2/19marchtestv2Folder.go b/generated-usage-examples/go/v2/19marchtestv2Folder.go similarity index 100% rename from generated-examples/go/v2/19marchtestv2Folder.go rename to generated-usage-examples/go/v2/19marchtestv2Folder.go diff --git a/generated-examples/go/view-index.snippet.example.go b/generated-usage-examples/go/view-index.snippet.example.go similarity index 100% rename from generated-examples/go/view-index.snippet.example.go rename to generated-usage-examples/go/view-index.snippet.example.go diff --git a/generated-examples/java/AnnQueryBasic.snippet.example.java b/generated-usage-examples/java/AnnQueryBasic.snippet.example.java similarity index 100% rename from generated-examples/java/AnnQueryBasic.snippet.example.java rename to generated-usage-examples/java/AnnQueryBasic.snippet.example.java diff --git a/generated-examples/java/AnnQueryFilter.snippet.example.java b/generated-usage-examples/java/AnnQueryFilter.snippet.example.java similarity index 100% rename from generated-examples/java/AnnQueryFilter.snippet.example.java rename to generated-usage-examples/java/AnnQueryFilter.snippet.example.java diff --git a/generated-examples/java/CreateIndexBasic.snippet.example.java b/generated-usage-examples/java/CreateIndexBasic.snippet.example.java similarity index 100% rename from generated-examples/java/CreateIndexBasic.snippet.example.java rename to generated-usage-examples/java/CreateIndexBasic.snippet.example.java diff --git a/generated-examples/java/CreateIndexFilter.snippet.example.java b/generated-usage-examples/java/CreateIndexFilter.snippet.example.java similarity index 100% rename from generated-examples/java/CreateIndexFilter.snippet.example.java rename to generated-usage-examples/java/CreateIndexFilter.snippet.example.java diff --git a/generated-examples/java/DropIndex.snippet.example.java b/generated-usage-examples/java/DropIndex.snippet.example.java similarity index 100% rename from generated-examples/java/DropIndex.snippet.example.java rename to generated-usage-examples/java/DropIndex.snippet.example.java diff --git a/generated-examples/java/ViewIndex.snippet.example.java b/generated-usage-examples/java/ViewIndex.snippet.example.java similarity index 100% rename from generated-examples/java/ViewIndex.snippet.example.java rename to generated-usage-examples/java/ViewIndex.snippet.example.java diff --git a/generated-examples/javascript/ann-query-basic.snippet.example.js b/generated-usage-examples/javascript/ann-query-basic.snippet.example.js similarity index 100% rename from generated-examples/javascript/ann-query-basic.snippet.example.js rename to generated-usage-examples/javascript/ann-query-basic.snippet.example.js diff --git a/generated-examples/javascript/ann-query-filter.snippet.example.js b/generated-usage-examples/javascript/ann-query-filter.snippet.example.js similarity index 100% rename from generated-examples/javascript/ann-query-filter.snippet.example.js rename to generated-usage-examples/javascript/ann-query-filter.snippet.example.js diff --git a/generated-examples/javascript/create-index-basic.snippet.example.js b/generated-usage-examples/javascript/create-index-basic.snippet.example.js similarity index 100% rename from generated-examples/javascript/create-index-basic.snippet.example.js rename to generated-usage-examples/javascript/create-index-basic.snippet.example.js diff --git a/generated-examples/javascript/create-index-filter.snippet.example.js b/generated-usage-examples/javascript/create-index-filter.snippet.example.js similarity index 100% rename from generated-examples/javascript/create-index-filter.snippet.example.js rename to generated-usage-examples/javascript/create-index-filter.snippet.example.js diff --git a/generated-examples/javascript/drop-index.snippet.example.js b/generated-usage-examples/javascript/drop-index.snippet.example.js similarity index 100% rename from generated-examples/javascript/drop-index.snippet.example.js rename to generated-usage-examples/javascript/drop-index.snippet.example.js diff --git a/generated-examples/javascript/view-index.snippet.example.js b/generated-usage-examples/javascript/view-index.snippet.example.js similarity index 100% rename from generated-examples/javascript/view-index.snippet.example.js rename to generated-usage-examples/javascript/view-index.snippet.example.js diff --git a/generated-examples/python/ann_basic.snippet.example.py b/generated-usage-examples/python/ann_basic.snippet.example.py similarity index 100% rename from generated-examples/python/ann_basic.snippet.example.py rename to generated-usage-examples/python/ann_basic.snippet.example.py diff --git a/generated-examples/python/ann_filter.snippet.example.py b/generated-usage-examples/python/ann_filter.snippet.example.py similarity index 100% rename from generated-examples/python/ann_filter.snippet.example.py rename to generated-usage-examples/python/ann_filter.snippet.example.py diff --git a/generated-examples/python/create_basic.snippet.example.py b/generated-usage-examples/python/create_basic.snippet.example.py similarity index 100% rename from generated-examples/python/create_basic.snippet.example.py rename to generated-usage-examples/python/create_basic.snippet.example.py diff --git a/generated-examples/python/create_filter.snippet.example.py b/generated-usage-examples/python/create_filter.snippet.example.py similarity index 100% rename from generated-examples/python/create_filter.snippet.example.py rename to generated-usage-examples/python/create_filter.snippet.example.py diff --git a/generated-examples/python/drop.snippet.example.py b/generated-usage-examples/python/drop.snippet.example.py similarity index 100% rename from generated-examples/python/drop.snippet.example.py rename to generated-usage-examples/python/drop.snippet.example.py diff --git a/generated-examples/python/langchain.snippet.example.py b/generated-usage-examples/python/langchain.snippet.example.py similarity index 100% rename from generated-examples/python/langchain.snippet.example.py rename to generated-usage-examples/python/langchain.snippet.example.py diff --git a/generated-examples/python/view.snippet.example.py b/generated-usage-examples/python/view.snippet.example.py similarity index 100% rename from generated-examples/python/view.snippet.example.py rename to generated-usage-examples/python/view.snippet.example.py diff --git a/go/README.md b/usage-examples/go/driver/README.md similarity index 100% rename from go/README.md rename to usage-examples/go/driver/README.md diff --git a/go/bluehawk.sh b/usage-examples/go/driver/bluehawk.sh similarity index 100% rename from go/bluehawk.sh rename to usage-examples/go/driver/bluehawk.sh diff --git a/go/examples/manage-indexes/IndexDefinition.go b/usage-examples/go/driver/examples/manage-indexes/IndexDefinition.go similarity index 100% rename from go/examples/manage-indexes/IndexDefinition.go rename to usage-examples/go/driver/examples/manage-indexes/IndexDefinition.go diff --git a/go/examples/manage-indexes/IndexExpectation.go b/usage-examples/go/driver/examples/manage-indexes/IndexExpectation.go similarity index 100% rename from go/examples/manage-indexes/IndexExpectation.go rename to usage-examples/go/driver/examples/manage-indexes/IndexExpectation.go diff --git a/go/examples/manage-indexes/create-index-basic.go b/usage-examples/go/driver/examples/manage-indexes/create-index-basic.go similarity index 100% rename from go/examples/manage-indexes/create-index-basic.go rename to usage-examples/go/driver/examples/manage-indexes/create-index-basic.go diff --git a/go/examples/manage-indexes/create-index-filter.go b/usage-examples/go/driver/examples/manage-indexes/create-index-filter.go similarity index 100% rename from go/examples/manage-indexes/create-index-filter.go rename to usage-examples/go/driver/examples/manage-indexes/create-index-filter.go diff --git a/go/examples/manage-indexes/drop-index.go b/usage-examples/go/driver/examples/manage-indexes/drop-index.go similarity index 100% rename from go/examples/manage-indexes/drop-index.go rename to usage-examples/go/driver/examples/manage-indexes/drop-index.go diff --git a/go/examples/manage-indexes/edit-index.go b/usage-examples/go/driver/examples/manage-indexes/edit-index.go similarity index 100% rename from go/examples/manage-indexes/edit-index.go rename to usage-examples/go/driver/examples/manage-indexes/edit-index.go diff --git a/go/examples/manage-indexes/verify-index-definition.go b/usage-examples/go/driver/examples/manage-indexes/verify-index-definition.go similarity index 100% rename from go/examples/manage-indexes/verify-index-definition.go rename to usage-examples/go/driver/examples/manage-indexes/verify-index-definition.go diff --git a/go/examples/manage-indexes/view-index.go b/usage-examples/go/driver/examples/manage-indexes/view-index.go similarity index 100% rename from go/examples/manage-indexes/view-index.go rename to usage-examples/go/driver/examples/manage-indexes/view-index.go diff --git a/go/examples/run-queries/ann-basic.go b/usage-examples/go/driver/examples/run-queries/ann-basic.go similarity index 100% rename from go/examples/run-queries/ann-basic.go rename to usage-examples/go/driver/examples/run-queries/ann-basic.go diff --git a/go/examples/run-queries/ann-filter.go b/usage-examples/go/driver/examples/run-queries/ann-filter.go similarity index 100% rename from go/examples/run-queries/ann-filter.go rename to usage-examples/go/driver/examples/run-queries/ann-filter.go diff --git a/go/examples/run-queries/enn.go b/usage-examples/go/driver/examples/run-queries/enn.go similarity index 100% rename from go/examples/run-queries/enn.go rename to usage-examples/go/driver/examples/run-queries/enn.go diff --git a/go/go.mod b/usage-examples/go/driver/go.mod similarity index 100% rename from go/go.mod rename to usage-examples/go/driver/go.mod diff --git a/go/go.sum b/usage-examples/go/driver/go.sum similarity index 100% rename from go/go.sum rename to usage-examples/go/driver/go.sum diff --git a/go/newgotestfile.go b/usage-examples/go/driver/newgotestfile.go similarity index 100% rename from go/newgotestfile.go rename to usage-examples/go/driver/newgotestfile.go diff --git a/go/ohhai_detete_me b/usage-examples/go/driver/ohhai_detete_me similarity index 100% rename from go/ohhai_detete_me rename to usage-examples/go/driver/ohhai_detete_me diff --git a/go/tests/manage-indexes/manage-indexes_test.go b/usage-examples/go/driver/tests/manage-indexes/manage-indexes_test.go similarity index 100% rename from go/tests/manage-indexes/manage-indexes_test.go rename to usage-examples/go/driver/tests/manage-indexes/manage-indexes_test.go diff --git a/go/tests/run-queries/VerifyMovieQueryOutput.go b/usage-examples/go/driver/tests/run-queries/VerifyMovieQueryOutput.go similarity index 100% rename from go/tests/run-queries/VerifyMovieQueryOutput.go rename to usage-examples/go/driver/tests/run-queries/VerifyMovieQueryOutput.go diff --git a/go/tests/run-queries/VerifyMovieQueryOutputWithFilter.go b/usage-examples/go/driver/tests/run-queries/VerifyMovieQueryOutputWithFilter.go similarity index 100% rename from go/tests/run-queries/VerifyMovieQueryOutputWithFilter.go rename to usage-examples/go/driver/tests/run-queries/VerifyMovieQueryOutputWithFilter.go diff --git a/go/tests/run-queries/run-queries_test.go b/usage-examples/go/driver/tests/run-queries/run-queries_test.go similarity index 100% rename from go/tests/run-queries/run-queries_test.go rename to usage-examples/go/driver/tests/run-queries/run-queries_test.go diff --git a/go/v22testfile2.go b/usage-examples/go/driver/v22testfile2.go similarity index 100% rename from go/v22testfile2.go rename to usage-examples/go/driver/v22testfile2.go diff --git a/java/README.md b/usage-examples/java/sync/README.md similarity index 100% rename from java/README.md rename to usage-examples/java/sync/README.md diff --git a/java/bluehawk.sh b/usage-examples/java/sync/bluehawk.sh similarity index 100% rename from java/bluehawk.sh rename to usage-examples/java/sync/bluehawk.sh diff --git a/java/pom.xml b/usage-examples/java/sync/pom.xml similarity index 100% rename from java/pom.xml rename to usage-examples/java/sync/pom.xml diff --git a/java/src/main/java/indexes/CreateIndexBasic.java b/usage-examples/java/sync/src/main/java/indexes/CreateIndexBasic.java similarity index 100% rename from java/src/main/java/indexes/CreateIndexBasic.java rename to usage-examples/java/sync/src/main/java/indexes/CreateIndexBasic.java diff --git a/java/src/main/java/indexes/CreateIndexFilter.java b/usage-examples/java/sync/src/main/java/indexes/CreateIndexFilter.java similarity index 100% rename from java/src/main/java/indexes/CreateIndexFilter.java rename to usage-examples/java/sync/src/main/java/indexes/CreateIndexFilter.java diff --git a/java/src/main/java/indexes/DropIndex.java b/usage-examples/java/sync/src/main/java/indexes/DropIndex.java similarity index 100% rename from java/src/main/java/indexes/DropIndex.java rename to usage-examples/java/sync/src/main/java/indexes/DropIndex.java diff --git a/java/src/main/java/indexes/ViewIndex.java b/usage-examples/java/sync/src/main/java/indexes/ViewIndex.java similarity index 100% rename from java/src/main/java/indexes/ViewIndex.java rename to usage-examples/java/sync/src/main/java/indexes/ViewIndex.java diff --git a/java/src/main/java/queries/AnnQueryBasic.java b/usage-examples/java/sync/src/main/java/queries/AnnQueryBasic.java similarity index 100% rename from java/src/main/java/queries/AnnQueryBasic.java rename to usage-examples/java/sync/src/main/java/queries/AnnQueryBasic.java diff --git a/java/src/main/java/queries/AnnQueryFilter.java b/usage-examples/java/sync/src/main/java/queries/AnnQueryFilter.java similarity index 100% rename from java/src/main/java/queries/AnnQueryFilter.java rename to usage-examples/java/sync/src/main/java/queries/AnnQueryFilter.java diff --git a/java/src/test/java/indexes/ManageIndexesTests.java b/usage-examples/java/sync/src/test/java/indexes/ManageIndexesTests.java similarity index 100% rename from java/src/test/java/indexes/ManageIndexesTests.java rename to usage-examples/java/sync/src/test/java/indexes/ManageIndexesTests.java diff --git a/java/src/test/java/indexes/models/Definition.java b/usage-examples/java/sync/src/test/java/indexes/models/Definition.java similarity index 100% rename from java/src/test/java/indexes/models/Definition.java rename to usage-examples/java/sync/src/test/java/indexes/models/Definition.java diff --git a/java/src/test/java/indexes/models/DefinitionVersion.java b/usage-examples/java/sync/src/test/java/indexes/models/DefinitionVersion.java similarity index 100% rename from java/src/test/java/indexes/models/DefinitionVersion.java rename to usage-examples/java/sync/src/test/java/indexes/models/DefinitionVersion.java diff --git a/java/src/test/java/indexes/models/Field.java b/usage-examples/java/sync/src/test/java/indexes/models/Field.java similarity index 100% rename from java/src/test/java/indexes/models/Field.java rename to usage-examples/java/sync/src/test/java/indexes/models/Field.java diff --git a/java/src/test/java/indexes/models/IndexDefinition.java b/usage-examples/java/sync/src/test/java/indexes/models/IndexDefinition.java similarity index 100% rename from java/src/test/java/indexes/models/IndexDefinition.java rename to usage-examples/java/sync/src/test/java/indexes/models/IndexDefinition.java diff --git a/java/src/test/java/indexes/models/MainIndex.java b/usage-examples/java/sync/src/test/java/indexes/models/MainIndex.java similarity index 100% rename from java/src/test/java/indexes/models/MainIndex.java rename to usage-examples/java/sync/src/test/java/indexes/models/MainIndex.java diff --git a/java/src/test/java/indexes/models/MongoDate.java b/usage-examples/java/sync/src/test/java/indexes/models/MongoDate.java similarity index 100% rename from java/src/test/java/indexes/models/MongoDate.java rename to usage-examples/java/sync/src/test/java/indexes/models/MongoDate.java diff --git a/java/src/test/java/indexes/models/StatusDetail.java b/usage-examples/java/sync/src/test/java/indexes/models/StatusDetail.java similarity index 100% rename from java/src/test/java/indexes/models/StatusDetail.java rename to usage-examples/java/sync/src/test/java/indexes/models/StatusDetail.java diff --git a/java/src/test/java/queries/QueryTests.java b/usage-examples/java/sync/src/test/java/queries/QueryTests.java similarity index 100% rename from java/src/test/java/queries/QueryTests.java rename to usage-examples/java/sync/src/test/java/queries/QueryTests.java diff --git a/javascript/README.md b/usage-examples/javascript/README.md similarity index 100% rename from javascript/README.md rename to usage-examples/javascript/README.md diff --git a/javascript/babel.config.cjs b/usage-examples/javascript/babel.config.cjs similarity index 100% rename from javascript/babel.config.cjs rename to usage-examples/javascript/babel.config.cjs diff --git a/javascript/bluehawk.sh b/usage-examples/javascript/bluehawk.sh similarity index 100% rename from javascript/bluehawk.sh rename to usage-examples/javascript/bluehawk.sh diff --git a/javascript/examples/indexes/create-index-basic.js b/usage-examples/javascript/examples/indexes/create-index-basic.js similarity index 100% rename from javascript/examples/indexes/create-index-basic.js rename to usage-examples/javascript/examples/indexes/create-index-basic.js diff --git a/javascript/examples/indexes/create-index-filter.js b/usage-examples/javascript/examples/indexes/create-index-filter.js similarity index 100% rename from javascript/examples/indexes/create-index-filter.js rename to usage-examples/javascript/examples/indexes/create-index-filter.js diff --git a/javascript/examples/indexes/drop-index.js b/usage-examples/javascript/examples/indexes/drop-index.js similarity index 100% rename from javascript/examples/indexes/drop-index.js rename to usage-examples/javascript/examples/indexes/drop-index.js diff --git a/javascript/examples/indexes/view-index.js b/usage-examples/javascript/examples/indexes/view-index.js similarity index 100% rename from javascript/examples/indexes/view-index.js rename to usage-examples/javascript/examples/indexes/view-index.js diff --git a/javascript/examples/queries/ann-query-basic.js b/usage-examples/javascript/examples/queries/ann-query-basic.js similarity index 100% rename from javascript/examples/queries/ann-query-basic.js rename to usage-examples/javascript/examples/queries/ann-query-basic.js diff --git a/javascript/examples/queries/ann-query-filter.js b/usage-examples/javascript/examples/queries/ann-query-filter.js similarity index 100% rename from javascript/examples/queries/ann-query-filter.js rename to usage-examples/javascript/examples/queries/ann-query-filter.js diff --git a/javascript/jest.config.cjs b/usage-examples/javascript/jest.config.cjs similarity index 100% rename from javascript/jest.config.cjs rename to usage-examples/javascript/jest.config.cjs diff --git a/javascript/package-lock.json b/usage-examples/javascript/package-lock.json similarity index 100% rename from javascript/package-lock.json rename to usage-examples/javascript/package-lock.json diff --git a/javascript/package.json b/usage-examples/javascript/package.json similarity index 100% rename from javascript/package.json rename to usage-examples/javascript/package.json diff --git a/javascript/tests/manage-indexes.test.js b/usage-examples/javascript/tests/manage-indexes.test.js similarity index 100% rename from javascript/tests/manage-indexes.test.js rename to usage-examples/javascript/tests/manage-indexes.test.js diff --git a/javascript/tests/run-queries.test.js b/usage-examples/javascript/tests/run-queries.test.js similarity index 100% rename from javascript/tests/run-queries.test.js rename to usage-examples/javascript/tests/run-queries.test.js diff --git a/python/README.md b/usage-examples/python/README.md similarity index 100% rename from python/README.md rename to usage-examples/python/README.md diff --git a/python/bluehawk.sh b/usage-examples/python/bluehawk.sh similarity index 100% rename from python/bluehawk.sh rename to usage-examples/python/bluehawk.sh diff --git a/python/examples/indexes/create_basic.py b/usage-examples/python/examples/indexes/create_basic.py similarity index 100% rename from python/examples/indexes/create_basic.py rename to usage-examples/python/examples/indexes/create_basic.py diff --git a/python/examples/indexes/create_filter.py b/usage-examples/python/examples/indexes/create_filter.py similarity index 100% rename from python/examples/indexes/create_filter.py rename to usage-examples/python/examples/indexes/create_filter.py diff --git a/python/examples/indexes/drop.py b/usage-examples/python/examples/indexes/drop.py similarity index 100% rename from python/examples/indexes/drop.py rename to usage-examples/python/examples/indexes/drop.py diff --git a/python/examples/indexes/view.py b/usage-examples/python/examples/indexes/view.py similarity index 100% rename from python/examples/indexes/view.py rename to usage-examples/python/examples/indexes/view.py diff --git a/python/examples/integration/langchain.py b/usage-examples/python/examples/integration/langchain.py similarity index 100% rename from python/examples/integration/langchain.py rename to usage-examples/python/examples/integration/langchain.py diff --git a/python/examples/queries/ann_basic.py b/usage-examples/python/examples/queries/ann_basic.py similarity index 100% rename from python/examples/queries/ann_basic.py rename to usage-examples/python/examples/queries/ann_basic.py diff --git a/python/examples/queries/ann_filter.py b/usage-examples/python/examples/queries/ann_filter.py similarity index 100% rename from python/examples/queries/ann_filter.py rename to usage-examples/python/examples/queries/ann_filter.py diff --git a/python/tests_package/test_manage_indexes.py b/usage-examples/python/tests_package/test_manage_indexes.py similarity index 100% rename from python/tests_package/test_manage_indexes.py rename to usage-examples/python/tests_package/test_manage_indexes.py diff --git a/python/tests_package/test_queries.py b/usage-examples/python/tests_package/test_queries.py similarity index 100% rename from python/tests_package/test_queries.py rename to usage-examples/python/tests_package/test_queries.py From b78cdc568bc0dc1406544c6dfc54b3f9a7f16b68 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 11 Mar 2025 09:53:22 -0400 Subject: [PATCH 02/22] Add internal functions for loading vars and creating authenticated client --- .gitignore | 3 +- usage-examples/go/admin-sdk/README.md | 22 ++++++ .../go/admin-sdk/config/config-example.json | 6 ++ .../go/admin-sdk/config/config.json | 6 ++ usage-examples/go/admin-sdk/go.mod | 13 ++++ usage-examples/go/admin-sdk/go.sum | 18 +++++ usage-examples/go/admin-sdk/internal/auth.go | 75 +++++++++++++++++++ .../go/admin-sdk/internal/config_loader.go | 43 +++++++++++ .../go/admin-sdk/internal/secrets_loader.go | 41 ++++++++++ usage-examples/go/admin-sdk/main.go | 21 ++++++ .../go/admin-sdk/scripts/pull_logs_metrics.go | 1 + 11 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 usage-examples/go/admin-sdk/README.md create mode 100644 usage-examples/go/admin-sdk/config/config-example.json create mode 100644 usage-examples/go/admin-sdk/config/config.json create mode 100644 usage-examples/go/admin-sdk/go.mod create mode 100644 usage-examples/go/admin-sdk/go.sum create mode 100644 usage-examples/go/admin-sdk/internal/auth.go create mode 100644 usage-examples/go/admin-sdk/internal/config_loader.go create mode 100644 usage-examples/go/admin-sdk/internal/secrets_loader.go create mode 100644 usage-examples/go/admin-sdk/main.go create mode 100644 usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go diff --git a/.gitignore b/.gitignore index d5149dd..86413d9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ ## Node.js dependencies */node_modules ## Java build files -*/target \ No newline at end of file +*/target + diff --git a/usage-examples/go/admin-sdk/README.md b/usage-examples/go/admin-sdk/README.md new file mode 100644 index 0000000..643d4fb --- /dev/null +++ b/usage-examples/go/admin-sdk/README.md @@ -0,0 +1,22 @@ +```text +my-go-project/ +│── scripts/ # ✅ Self-contained, runnable scripts +│ ├── get_invoices.go # Script to fetch invoices +│ ├── fetch_logs.go # Script to retrieve logs +│ ├── delete_old_data.go # Script to delete data +│── config/ # ✅ Configuration directory +│ ├── config.json # General app settings (non-sensitive) +│ ├── logging.json # Logging settings +│ ├── database.json # Database settings (no credentials) +│ ├── features.json # Feature flags and toggles +│── secrets/ # ✅ Secure secrets directory (excluded from Git) +│ ├── secrets.json # 🔐 API keys, database credentials +│── internal/ # ✅ Shared internal logic +│ ├── config_loader.go # Loads JSON configs +│ ├── secrets_loader.go # Loads secrets securely +│── .gitignore # Exclude secrets.json +│── go.mod # Go module file +│── go.sum # Dependency checksums +│── README.md # Documentation + +``` diff --git a/usage-examples/go/admin-sdk/config/config-example.json b/usage-examples/go/admin-sdk/config/config-example.json new file mode 100644 index 0000000..6bcf8b8 --- /dev/null +++ b/usage-examples/go/admin-sdk/config/config-example.json @@ -0,0 +1,6 @@ +{ + "BASEURL": "", + "PAYING_ORG_ID": "", + "ORG_ID": "" +} diff --git a/usage-examples/go/admin-sdk/config/config.json b/usage-examples/go/admin-sdk/config/config.json new file mode 100644 index 0000000..ff9d2e8 --- /dev/null +++ b/usage-examples/go/admin-sdk/config/config.json @@ -0,0 +1,6 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "GROUP_ID": "634f247c3e5f8207b4de5766", + "BILL_PAYING_ORG_ID": "65c13caadadd2d64cf8fcaf0", + "ORG_ID": "65c13caadadd2d64cf8fcaf0" +} diff --git a/usage-examples/go/admin-sdk/go.mod b/usage-examples/go/admin-sdk/go.mod new file mode 100644 index 0000000..33406c3 --- /dev/null +++ b/usage-examples/go/admin-sdk/go.mod @@ -0,0 +1,13 @@ +module admin-sdk + +go 1.24 + +require ( + github.com/joho/godotenv v1.5.1 + go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 +) + +require ( + github.com/mongodb-forks/digest v1.1.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect +) diff --git a/usage-examples/go/admin-sdk/go.sum b/usage-examples/go/admin-sdk/go.sum new file mode 100644 index 0000000..21e7dad --- /dev/null +++ b/usage-examples/go/admin-sdk/go.sum @@ -0,0 +1,18 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKksrOoc= +github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= +go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/usage-examples/go/admin-sdk/internal/auth.go b/usage-examples/go/admin-sdk/internal/auth.go new file mode 100644 index 0000000..7b65287 --- /dev/null +++ b/usage-examples/go/admin-sdk/internal/auth.go @@ -0,0 +1,75 @@ +package internal + +import ( + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "os" +) + +// CreateAtlasClient initializes and returns an authenticated Atlas API client. +func CreateAtlasClient() (*admin.APIClient, error) { + + // Load secrets + secrets, err := LoadSecrets() + if err != nil { + return nil, fmt.Errorf("failed to load secrets: %w", err) + } else { + fmt.Println("Secrets loaded successfully") + } + + // Print loaded secrets for debugging + fmt.Printf("Loaded Secrets: %+v\n", secrets) + + // Check for missing credentials + if secrets.ClientID == "" || secrets.ClientSecret == "" { + return nil, fmt.Errorf("missing Atlas client credentials") + } + fmt.Println("Client credentials are present") + + // Load configuration + config, err := LoadConfig("config/config.json") + if err != nil { + return nil, fmt.Errorf("failed to load config file: %w", err) + } + + // Determine base URL + host := config.BaseURL + if host == "" { + host = os.Getenv("ATLAS_BASE_URL") + } + if host == "" { + host = "https://cloud.mongodb.com" + } + fmt.Println("Using Atlas Base URL:", host) + + // Initialize API client + ctx := context.Background() + sdk, err := admin.NewClient( + admin.UseBaseURL(host), + admin.UseOAuthAuth(ctx, secrets.ClientID, secrets.ClientSecret), + ) + if err != nil { + return nil, fmt.Errorf("error creating SDK client: %w", err) + } + fmt.Println("SDK client created successfully") + + // Determine org ID + orgID := config.OrgID + if orgID == "" { + orgID = os.Getenv("ATLAS_ORG_ID") + } + if orgID == "" { + orgs, _, err := sdk.OrganizationsApi.ListOrganizations(ctx).Execute() + if err != nil { + return nil, fmt.Errorf("error listing organizations: %w", err) + } + if orgs.GetTotalCount() == 0 { + return nil, fmt.Errorf("no organizations found") + } + orgID = orgs.GetResults()[0].GetId() + fmt.Printf("Using organization %s\n", orgID) + } + + return sdk, nil +} diff --git a/usage-examples/go/admin-sdk/internal/config_loader.go b/usage-examples/go/admin-sdk/internal/config_loader.go new file mode 100644 index 0000000..b52fa82 --- /dev/null +++ b/usage-examples/go/admin-sdk/internal/config_loader.go @@ -0,0 +1,43 @@ +package internal + +import ( + "encoding/json" + "fmt" + "os" +) + +/* GetConfigFilePath returns the correct config file based on the environment +used in projects with multiple configs for different environments +*/ + +type Config struct { + BaseURL string `json:"ATLAS_BASE_URL"` + GroupID string `json:"GROUP_ID"` + BillPayingOrgID string `json:"BILL_PAYING_ORG_ID"` + OrgID string `json:"ORG_ID"` +} + +//func GetConfigFilePath() string { +// env := os.Getenv("APP_ENV") // "dev", "prod", "staging" +// if env == "" { +// env = "dev" // Default to development +// } +// return fmt.Sprintf("config/config-%s.json", env) +//} + +// LoadConfig loads a JSON config file into a Config struct +// takes a file path as an argument and returns a pointer to a Config struct and an error +func LoadConfig(filePath string) (*Config, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("error opening config file: %w", err) + } + defer file.Close() + + var config Config + decoder := json.NewDecoder(file) + if err := decoder.Decode(&config); err != nil { + return nil, fmt.Errorf("error decoding config file: %w", err) + } + return &config, nil +} diff --git a/usage-examples/go/admin-sdk/internal/secrets_loader.go b/usage-examples/go/admin-sdk/internal/secrets_loader.go new file mode 100644 index 0000000..5cb81e8 --- /dev/null +++ b/usage-examples/go/admin-sdk/internal/secrets_loader.go @@ -0,0 +1,41 @@ +package internal + +import ( + "fmt" + "github.com/joho/godotenv" + "log" + "os" +) + +// Secrets structure +type Secrets struct { + DBUser string `json:"DB_USER"` + DBPassword string `json:"DB_PASSWORD"` + APIKey string `json:"PUBLIC_API_KEY"` + PrivateKey string `json:"PRIVATE_API_KEY"` + ClientID string `json:"ATLAS_CLIENT_ID"` + ClientSecret string `json:"ATLAS_CLIENT_SECRET"` +} + +// LoadEnv loads environment variables from a .env file +func LoadEnv() { + err := godotenv.Load(".env") + if err != nil { + log.Fatalf("Error loading .env file") + } +} + +// LoadSecrets loads a JSON secrets file into a Secrets struct +// takes a file path as an argument and returns a pointer to a Secrets struct and an error +func LoadSecrets() (*Secrets, error) { + secrets := &Secrets{ + DBUser: os.Getenv("DB_USER"), + DBPassword: os.Getenv("DB_PASSWORD"), + APIKey: os.Getenv("PUBLIC_API_KEY"), + PrivateKey: os.Getenv("PRIVATE_API_KEY"), + ClientID: os.Getenv("ATLAS_CLIENT_ID"), + ClientSecret: os.Getenv("ATLAS_CLIENT_SECRET"), + } + fmt.Printf("Loaded Secrets Debug: %+v\n", secrets) // Debug print + return secrets, nil +} diff --git a/usage-examples/go/admin-sdk/main.go b/usage-examples/go/admin-sdk/main.go new file mode 100644 index 0000000..31120d6 --- /dev/null +++ b/usage-examples/go/admin-sdk/main.go @@ -0,0 +1,21 @@ +package testing + +import ( + "admin-sdk/internal" + "fmt" + "os" +) + +func main() { + internal.LoadEnv() + // Verify they are set + fmt.Println("ATLAS_CLIENT_ID:", os.Getenv("ATLAS_CLIENT_ID")) + fmt.Println("ATLAS_CLIENT_SECRET:", os.Getenv("ATLAS_CLIENT_SECRET")) + + // Now you can call LoadSecrets() without needing to manually set env vars + secrets, _ := internal.LoadSecrets() + fmt.Printf("Loaded Secrets: %+v\n", secrets) + + // Now you can call CreateAtlasClient() without needing to manually set env vars + internal.CreateAtlasClient() +} diff --git a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go @@ -0,0 +1 @@ +package main From f6a1b41ebc2b0456ff5b5003131423cc5092aec2 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 13 Mar 2025 06:50:50 -0400 Subject: [PATCH 03/22] Add infra and pull logs script --- .../go/admin-sdk/config/config.json | 3 +- usage-examples/go/admin-sdk/internal/auth.go | 16 +-- .../go/admin-sdk/scripts/pull_logs_metrics.go | 134 ++++++++++++++++++ usage-examples/go/admin-sdk/utils/utility.go | 1 + 4 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 usage-examples/go/admin-sdk/utils/utility.go diff --git a/usage-examples/go/admin-sdk/config/config.json b/usage-examples/go/admin-sdk/config/config.json index ff9d2e8..d629e24 100644 --- a/usage-examples/go/admin-sdk/config/config.json +++ b/usage-examples/go/admin-sdk/config/config.json @@ -2,5 +2,6 @@ "ATLAS_BASE_URL": "https://cloud.mongodb.com", "GROUP_ID": "634f247c3e5f8207b4de5766", "BILL_PAYING_ORG_ID": "65c13caadadd2d64cf8fcaf0", - "ORG_ID": "65c13caadadd2d64cf8fcaf0" + "ORG_ID": "65c13caadadd2d64cf8fcaf0", + "CLUSTER_NAME": "Cluster0" } diff --git a/usage-examples/go/admin-sdk/internal/auth.go b/usage-examples/go/admin-sdk/internal/auth.go index 7b65287..cc30b67 100644 --- a/usage-examples/go/admin-sdk/internal/auth.go +++ b/usage-examples/go/admin-sdk/internal/auth.go @@ -8,12 +8,12 @@ import ( ) // CreateAtlasClient initializes and returns an authenticated Atlas API client. -func CreateAtlasClient() (*admin.APIClient, error) { +func CreateAtlasClient() (*admin.APIClient, *Config, error) { // Load secrets secrets, err := LoadSecrets() if err != nil { - return nil, fmt.Errorf("failed to load secrets: %w", err) + return nil, nil, fmt.Errorf("failed to load secrets: %w", err) } else { fmt.Println("Secrets loaded successfully") } @@ -23,14 +23,14 @@ func CreateAtlasClient() (*admin.APIClient, error) { // Check for missing credentials if secrets.ClientID == "" || secrets.ClientSecret == "" { - return nil, fmt.Errorf("missing Atlas client credentials") + return nil, nil, fmt.Errorf("missing Atlas client credentials") } fmt.Println("Client credentials are present") // Load configuration config, err := LoadConfig("config/config.json") if err != nil { - return nil, fmt.Errorf("failed to load config file: %w", err) + return nil, nil, fmt.Errorf("failed to load config file: %w", err) } // Determine base URL @@ -50,7 +50,7 @@ func CreateAtlasClient() (*admin.APIClient, error) { admin.UseOAuthAuth(ctx, secrets.ClientID, secrets.ClientSecret), ) if err != nil { - return nil, fmt.Errorf("error creating SDK client: %w", err) + return nil, nil, fmt.Errorf("error creating SDK client: %w", err) } fmt.Println("SDK client created successfully") @@ -62,14 +62,14 @@ func CreateAtlasClient() (*admin.APIClient, error) { if orgID == "" { orgs, _, err := sdk.OrganizationsApi.ListOrganizations(ctx).Execute() if err != nil { - return nil, fmt.Errorf("error listing organizations: %w", err) + return nil, nil, fmt.Errorf("error listing organizations: %w", err) } if orgs.GetTotalCount() == 0 { - return nil, fmt.Errorf("no organizations found") + return nil, nil, fmt.Errorf("no organizations found") } orgID = orgs.GetResults()[0].GetId() fmt.Printf("Using organization %s\n", orgID) } - return sdk, nil + return sdk, config, nil } diff --git a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go index 06ab7d0..4829148 100644 --- a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go +++ b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go @@ -1 +1,135 @@ package main + +import ( + "admin-sdk/internal" + "context" + "encoding/json" + "flag" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" + "time" +) + +func main() { + ctx := context.Background() + + // CLI Flags + projectID := flag.String("project", "", "Atlas project ID") + hostName := flag.String("host", "", "Hostname of the process") + logName := flag.String("log", "mongos", "Log name to fetch") + interval := flag.Int("interval", 0, "Fetch interval in minutes (0 for one-time run)") + // configPath := flag.String("config", "config/config.json", "Path to JSON config file") + flag.Parse() + + // Load Configuration and Authenticate + sdk, config, err := internal.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Override config values with CLI flags if provided + cfgProjectID := firstNonEmpty(*projectID, config.GroupID) + cfgHostName := *hostName // No default, must be provided + cfgLogName := firstNonEmpty(*logName, "mongos") + cfgInterval := firstNonZero(*interval, 0) + + // Ensure required values are set + if cfgProjectID == "" { + log.Fatal("Project ID is required (pass --project flag or set GROUP_ID in config)") + } + if cfgHostName == "" { + log.Fatal("Host name is required (pass --host flag)") + } + + // Loop for repeated execution if interval is set + for { + if err := fetchLogs(ctx, sdk, cfgProjectID, cfgHostName, cfgLogName); err != nil { + log.Printf("Error fetching logs: %v", err) + } + + if cfgInterval == 0 { + break + } + time.Sleep(time.Duration(cfgInterval) * time.Minute) + } + // Fetch metrics + if err := fetchMetrics(ctx, sdk, cfgProjectID, cfgHostName); err != nil { + log.Printf("Error fetching metrics: %v", err) + } +} + +func fetchLogs(ctx context.Context, sdk *admin.APIClient, projectID, hostName, logName string) error { + fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", projectID, hostName, logName) + + resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ + GroupId: projectID, + HostName: hostName, + LogName: logName, + }).Execute() + if err != nil { + return fmt.Errorf("failed to get logs: %w", err) + } + defer resp.Close() + + logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", projectID, hostName)) + if err != nil { + return fmt.Errorf("failed to create log file: %w", err) + } + defer logFile.Close() + + _, err = io.Copy(logFile, resp) + if err != nil { + return fmt.Errorf("failed to save logs: %w", err) + } + fmt.Println("Logs saved.") + + return nil +} + +func fetchMetrics(ctx context.Context, sdk *admin.APIClient, projectID, hostName string) error { + fmt.Printf("Fetching metrics for project %s, host %s...\n\n", projectID, hostName) + + resp, _, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, &admin.GetMeasurementsApiParams{ + GroupId: projectID, + HostName: hostName, + "SYSTEM"}).Execute() + if err != nil { + return fmt.Errorf("failed to fetch metrics: %w", err) + } + + metricsFile, err := os.Create(fmt.Sprintf("metrics_%s_%s.json", projectID, hostName)) + if err != nil { + return fmt.Errorf("failed to create metrics file: %w", err) + } + defer metricsFile.Close() + + json.NewEncoder(metricsFile).Encode(resp) + fmt.Println("Metrics saved.") + return nil +} + +func getHostNameFromID(ctx context.Context, sdk *admin.APIClient, projectID string) (string, error) { + resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, projectID).Execute() + if err != nil { + return "", fmt.Errorf("failed to get host: %w", err) + } + return resp.HostName, nil +} + +// Utility functions +func firstNonEmpty(cli, config string) string { + if cli != "" { + return cli + } + return config +} + +func firstNonZero(cli, config int) int { + if cli != 0 { + return cli + } + return config +} diff --git a/usage-examples/go/admin-sdk/utils/utility.go b/usage-examples/go/admin-sdk/utils/utility.go new file mode 100644 index 0000000..d4b585b --- /dev/null +++ b/usage-examples/go/admin-sdk/utils/utility.go @@ -0,0 +1 @@ +package utils From f69498b34764b25f157c12965eccefff2a99febc Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 13 Mar 2025 13:46:00 -0400 Subject: [PATCH 04/22] Add utility functions and troubleshoot metrics calls --- .../go/admin-sdk/config/config.json | 6 +- usage-examples/go/admin-sdk/internal/auth.go | 16 +- .../go/admin-sdk/internal/secrets_loader.go | 1 + .../go/admin-sdk/scripts/get_hosts.go | 57 ++++++ .../go/admin-sdk/scripts/pull_logs_metrics.go | 169 +++++++++++------- usage-examples/go/admin-sdk/utils/utility.go | 21 +++ 6 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 usage-examples/go/admin-sdk/scripts/get_hosts.go diff --git a/usage-examples/go/admin-sdk/config/config.json b/usage-examples/go/admin-sdk/config/config.json index d629e24..8d8cc8d 100644 --- a/usage-examples/go/admin-sdk/config/config.json +++ b/usage-examples/go/admin-sdk/config/config.json @@ -1,7 +1,7 @@ { "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "GROUP_ID": "634f247c3e5f8207b4de5766", - "BILL_PAYING_ORG_ID": "65c13caadadd2d64cf8fcaf0", - "ORG_ID": "65c13caadadd2d64cf8fcaf0", + "GROUP_ID": "5f60207f14dfb25d23101102", + "BILL_PAYING_ORG_ID": "5bfda007553855125605a5cf", + "ORG_ID": "5bfda007553855125605a5cf", "CLUSTER_NAME": "Cluster0" } diff --git a/usage-examples/go/admin-sdk/internal/auth.go b/usage-examples/go/admin-sdk/internal/auth.go index cc30b67..4e413a6 100644 --- a/usage-examples/go/admin-sdk/internal/auth.go +++ b/usage-examples/go/admin-sdk/internal/auth.go @@ -8,12 +8,12 @@ import ( ) // CreateAtlasClient initializes and returns an authenticated Atlas API client. -func CreateAtlasClient() (*admin.APIClient, *Config, error) { +func CreateAtlasClient() (*admin.APIClient, *Secrets, *Config, error) { // Load secrets secrets, err := LoadSecrets() if err != nil { - return nil, nil, fmt.Errorf("failed to load secrets: %w", err) + return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) } else { fmt.Println("Secrets loaded successfully") } @@ -23,14 +23,14 @@ func CreateAtlasClient() (*admin.APIClient, *Config, error) { // Check for missing credentials if secrets.ClientID == "" || secrets.ClientSecret == "" { - return nil, nil, fmt.Errorf("missing Atlas client credentials") + return nil, nil, nil, fmt.Errorf("missing Atlas client credentials") } fmt.Println("Client credentials are present") // Load configuration config, err := LoadConfig("config/config.json") if err != nil { - return nil, nil, fmt.Errorf("failed to load config file: %w", err) + return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) } // Determine base URL @@ -50,7 +50,7 @@ func CreateAtlasClient() (*admin.APIClient, *Config, error) { admin.UseOAuthAuth(ctx, secrets.ClientID, secrets.ClientSecret), ) if err != nil { - return nil, nil, fmt.Errorf("error creating SDK client: %w", err) + return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) } fmt.Println("SDK client created successfully") @@ -62,14 +62,14 @@ func CreateAtlasClient() (*admin.APIClient, *Config, error) { if orgID == "" { orgs, _, err := sdk.OrganizationsApi.ListOrganizations(ctx).Execute() if err != nil { - return nil, nil, fmt.Errorf("error listing organizations: %w", err) + return nil, nil, nil, fmt.Errorf("error listing organizations: %w", err) } if orgs.GetTotalCount() == 0 { - return nil, nil, fmt.Errorf("no organizations found") + return nil, nil, nil, fmt.Errorf("no organizations found") } orgID = orgs.GetResults()[0].GetId() fmt.Printf("Using organization %s\n", orgID) } - return sdk, config, nil + return sdk, secrets, config, nil } diff --git a/usage-examples/go/admin-sdk/internal/secrets_loader.go b/usage-examples/go/admin-sdk/internal/secrets_loader.go index 5cb81e8..6495c4a 100644 --- a/usage-examples/go/admin-sdk/internal/secrets_loader.go +++ b/usage-examples/go/admin-sdk/internal/secrets_loader.go @@ -28,6 +28,7 @@ func LoadEnv() { // LoadSecrets loads a JSON secrets file into a Secrets struct // takes a file path as an argument and returns a pointer to a Secrets struct and an error func LoadSecrets() (*Secrets, error) { + LoadEnv() secrets := &Secrets{ DBUser: os.Getenv("DB_USER"), DBPassword: os.Getenv("DB_PASSWORD"), diff --git a/usage-examples/go/admin-sdk/scripts/get_hosts.go b/usage-examples/go/admin-sdk/scripts/get_hosts.go new file mode 100644 index 0000000..8bcfcf7 --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/get_hosts.go @@ -0,0 +1,57 @@ +package main + +import ( + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "os" +) + +// GetHostNameFromID retrieves the hostname of a process in an Atlas project. + +func GetHostName(ctx context.Context, sdk *admin.APIClient, groupId string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { + resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) + apiError, ok := admin.AsError(err) + if ok { + fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) + } + // response from `ListAtlasProcesses`: PaginatedHostViewAtlas + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) + } + + return resp, nil +} + +//func getHostFromID(ctx context.Context, sdk *admin.APIClient, groupId, processId string) (string, error) { +// resp, r, err := sdk.MonitoringAndLogsApi.GetAtlasProcess(ctx, groupId, processId).Execute() +// if err != nil { +// fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetProcess`: %v (%v)\n", err, r) +// apiError, ok := admin.AsError(err) +// if ok { +// fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) +// } +// // response from `GetProcess`: Process +// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetProcess`: %v (%v)\n", resp, r) +// } +// return resp.GetHostname(), nil +//} +// +//func main() { +// +// // Initialize Atlas client +// sdk, config, err := internal.CreateAtlasClient() +// if err != nil { +// fmt.Printf("failed to create Atlas client: %v\n", err) +// } +// +// // Get host name +// hostName, err := ListProcesses(context.Background(), sdk, config.GroupID) +// if err != nil { +// fmt.Printf("failed to get host name: %v\n", err) +// return +// } +// +// fmt.Println("Host name:", hostName) +//} diff --git a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go index 4829148..652900a 100644 --- a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go +++ b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go @@ -2,8 +2,8 @@ package main import ( "admin-sdk/internal" + "admin-sdk/utils" "context" - "encoding/json" "flag" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" @@ -13,41 +13,92 @@ import ( "time" ) +//type Metric struct { +// processID string +// groupID string +// granularity string +// metrics []string +// period *string +// start *time.Time +// end *time.Time +//} + func main() { ctx := context.Background() // CLI Flags projectID := flag.String("project", "", "Atlas project ID") - hostName := flag.String("host", "", "Hostname of the process") - logName := flag.String("log", "mongos", "Log name to fetch") + logName := flag.String("log", "mongodb", "Log name to fetch") interval := flag.Int("interval", 0, "Fetch interval in minutes (0 for one-time run)") - // configPath := flag.String("config", "config/config.json", "Path to JSON config file") + // granularity := flag.String("granularity", "PT1M", "Granularity of the metrics") + // metrics := flag.String("metrics", "", "Comma-separated list of metrics to fetch") flag.Parse() // Load Configuration and Authenticate - sdk, config, err := internal.CreateAtlasClient() + sdk, secrets, config, err := internal.CreateAtlasClient() if err != nil { log.Fatalf("Failed to create Atlas client: %v", err) } // Override config values with CLI flags if provided - cfgProjectID := firstNonEmpty(*projectID, config.GroupID) - cfgHostName := *hostName // No default, must be provided - cfgLogName := firstNonEmpty(*logName, "mongos") - cfgInterval := firstNonZero(*interval, 0) + cfgProjectID := utils.FirstNonEmpty(*projectID, config.GroupID) + cfgLogName := utils.FirstNonEmpty(*logName, "mongodb") + cfgInterval := utils.FirstNonZero(*interval, 0) + // cfgMetrics := utils.FirstNonEmpty(*metrics, "") + // cfgGranularity := utils.FirstNonEmpty(*granularity, "") // Ensure required values are set if cfgProjectID == "" { log.Fatal("Project ID is required (pass --project flag or set GROUP_ID in config)") } - if cfgHostName == "" { - log.Fatal("Host name is required (pass --host flag)") + //metrics := []string{"SYSTEM"} + //measurement := []string{""} + granularity := "PT1M" + period := "PT10H" + //metrics := []String + //if metrics == "" { + // metrics = strings.Split(*metrics, ",") + //} + //if cfgGranularity == "" { + // cfgGranularity = *granularity + //} + fmt.Println("DEBUG: Calling ListAtlasProcesses with GroupID:", cfgProjectID) + fmt.Printf("DEBUG: SDK Config: %+v\n", sdk) + fmt.Println("DEBUG: Using ClientID:", secrets.ClientID) + fmt.Println("DEBUG: Using ClientSecret Length:", len(secrets.ClientSecret)) + + // Fetch all processes in the project to get hostnames + processes, err := fetchProcesses(ctx, sdk, cfgProjectID, false, 100, 1) + if err != nil { + log.Fatalf("Failed to fetch processes: %v", err) + } + + // Extract host names and process IDs from the response + var processIDs []string + var hostNames []string + if processes.Results != nil { + for _, process := range *processes.Results { + if process.Id != nil { + processIDs = append(processIDs, *process.Id) + } + if process.Hostname != nil { + hostNames = append(hostNames, *process.Hostname) + } + } + } else { + log.Fatal("No processes found in the project") } - // Loop for repeated execution if interval is set + // Loop through each host and fetch logs & metrics for { - if err := fetchLogs(ctx, sdk, cfgProjectID, cfgHostName, cfgLogName); err != nil { - log.Printf("Error fetching logs: %v", err) + for i := range processIDs { + if err := fetchHostLogs(ctx, sdk, cfgProjectID, hostNames[i], cfgLogName); err != nil { + log.Printf("Error fetching logs for %s: %v", processIDs[i], err) + } + + if err := fetchHostMetrics(ctx, sdk, cfgProjectID, processIDs[i], granularity, period); err != nil { + log.Printf("Error fetching metrics for %s: %v", processIDs[i], err) + } } if cfgInterval == 0 { @@ -55,26 +106,24 @@ func main() { } time.Sleep(time.Duration(cfgInterval) * time.Minute) } - // Fetch metrics - if err := fetchMetrics(ctx, sdk, cfgProjectID, cfgHostName); err != nil { - log.Printf("Error fetching metrics: %v", err) - } } -func fetchLogs(ctx context.Context, sdk *admin.APIClient, projectID, hostName, logName string) error { - fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", projectID, hostName, logName) +// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz +func fetchHostLogs(ctx context.Context, sdk *admin.APIClient, groupID, hostName, logName string) error { + fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", groupID, hostName, logName) + + req := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName) + fmt.Println("DEBUG: Generated Fetch Logs API request:", req) - resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ - GroupId: projectID, - HostName: hostName, - LogName: logName, - }).Execute() + resp, _, err := req.Execute() + //resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName).Execute() + //dk.MonitoringAndLogsAPI.GetHostLogs(ctx, groupID, hostName, logName).Execute() if err != nil { return fmt.Errorf("failed to get logs: %w", err) } defer resp.Close() - logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", projectID, hostName)) + logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", groupID, hostName)) if err != nil { return fmt.Errorf("failed to create log file: %w", err) } @@ -89,47 +138,47 @@ func fetchLogs(ctx context.Context, sdk *admin.APIClient, projectID, hostName, l return nil } -func fetchMetrics(ctx context.Context, sdk *admin.APIClient, projectID, hostName string) error { - fmt.Printf("Fetching metrics for project %s, host %s...\n\n", projectID, hostName) +//https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/processes/{processId}/measurements - resp, _, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, &admin.GetMeasurementsApiParams{ - GroupId: projectID, - HostName: hostName, - "SYSTEM"}).Execute() - if err != nil { - return fmt.Errorf("failed to fetch metrics: %w", err) - } +func fetchHostMetrics(ctx context.Context, sdk *admin.APIClient, groupID, processID, granularity, period string) error { + //fmt.Printf("Fetching metrics for project %s ...\n\n", groupID) + fmt.Printf("DEBUG: Fetching metrics for GroupID: %s, ProcessID: %s, Granularity: %s\n", groupID, processID, granularity, period) + // Simulate request construction + req := sdk.MonitoringAndLogsApi.GetHostMeasurements(ctx, groupID, processID). + Granularity(granularity).Period(period) - metricsFile, err := os.Create(fmt.Sprintf("metrics_%s_%s.json", projectID, hostName)) - if err != nil { - return fmt.Errorf("failed to create metrics file: %w", err) - } - defer metricsFile.Close() + fmt.Println("DEBUG: Generated API request:", req) - json.NewEncoder(metricsFile).Encode(resp) - fmt.Println("Metrics saved.") - return nil -} - -func getHostNameFromID(ctx context.Context, sdk *admin.APIClient, projectID string) (string, error) { - resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, projectID).Execute() + resp, r, err := req.Execute() if err != nil { - return "", fmt.Errorf("failed to get host: %w", err) + fmt.Fprintf(os.Stderr, "Error when calling `GetMeasurements`: %v (%v)\n", err, r) + return err } - return resp.HostName, nil + //resp, r, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, groupID, processID).Granularity(granularity).Metrics(metrics).Execute() + //if err != nil { + // fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", err, r) + // apiError, ok := admin.AsError(err) + // if ok { + // fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) + // } + //} + // response from `GetMeasurements`: MeasurementsNonIndex + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", resp, r) + return nil } -// Utility functions -func firstNonEmpty(cli, config string) string { - if cli != "" { - return cli - } - return config -} +// GetHostNameFromID retrieves the hostname of a process in an Atlas project. -func firstNonZero(cli, config int) int { - if cli != 0 { - return cli +func fetchProcesses(ctx context.Context, sdk *admin.APIClient, groupID string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { + resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupID).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) + apiError, ok := admin.AsError(err) + if ok { + fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) + } + // response from `ListAtlasProcesses`: PaginatedHostViewAtlas + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) } - return config + return resp, nil } diff --git a/usage-examples/go/admin-sdk/utils/utility.go b/usage-examples/go/admin-sdk/utils/utility.go index d4b585b..a90b407 100644 --- a/usage-examples/go/admin-sdk/utils/utility.go +++ b/usage-examples/go/admin-sdk/utils/utility.go @@ -1 +1,22 @@ package utils + +// Utility functions +func FirstNonEmpty(cli, config string) string { + if cli != "" { + return cli + } + return config +} +func FirstNonEmptyArray(cli, config []string) []string { + if len(cli) > 0 { + return cli + } + return config +} + +func FirstNonZero(cli, config int) int { + if cli != 0 { + return cli + } + return config +} From 40aee9943305aa03f2f8f936f093941c79b5e563 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 14 Mar 2025 11:44:23 -0400 Subject: [PATCH 05/22] Fix metric outputs --- .../go/admin-sdk/internal/secrets_loader.go | 2 - .../go/admin-sdk/scripts/get_logs_metrics.go | 227 ++++++++++++++++++ usage-examples/go/admin-sdk/scripts/types.go | 44 ++++ 3 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 usage-examples/go/admin-sdk/scripts/get_logs_metrics.go create mode 100644 usage-examples/go/admin-sdk/scripts/types.go diff --git a/usage-examples/go/admin-sdk/internal/secrets_loader.go b/usage-examples/go/admin-sdk/internal/secrets_loader.go index 6495c4a..34c95f3 100644 --- a/usage-examples/go/admin-sdk/internal/secrets_loader.go +++ b/usage-examples/go/admin-sdk/internal/secrets_loader.go @@ -1,7 +1,6 @@ package internal import ( - "fmt" "github.com/joho/godotenv" "log" "os" @@ -37,6 +36,5 @@ func LoadSecrets() (*Secrets, error) { ClientID: os.Getenv("ATLAS_CLIENT_ID"), ClientSecret: os.Getenv("ATLAS_CLIENT_SECRET"), } - fmt.Printf("Loaded Secrets Debug: %+v\n", secrets) // Debug print return secrets, nil } diff --git a/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go new file mode 100644 index 0000000..ae6d271 --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go @@ -0,0 +1,227 @@ +package main + +import ( + "admin-sdk/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" +) + +func main() { + ctx := context.TODO() + + sdk, _, config, err := internal.CreateAtlasClient() + if err != nil { + log.Fatalf("Error creating Atlas client: %v", err) + } + + // Get the list of projects to retrieve the group ID + projectParams := &ListProjectsParams{ + GroupID: config.GroupID, + ItemsPerPage: admin.PtrInt(1), + IncludeCount: admin.PtrBool(true), + PageNum: admin.PtrInt(1), + } + projects, err := getProjectList(ctx, sdk, projectParams) + if err != nil { + log.Fatalf("Error getting projects: %v", err) + } + projectId := projects.GetResults()[0].Id + + if config.GroupID == "" { + config.GroupID = *projectId + } + + processParams := &ListAtlasProcessesParams{ + GroupID: config.GroupID, + IncludeCount: admin.PtrBool(true), + ItemsPerPage: admin.PtrInt(1), + PageNum: admin.PtrInt(1), + } + hosts, err := getProcessList(ctx, sdk, processParams) + if err != nil { + log.Fatalf("Error getting processes: %v", err) + } + hostName := hosts.GetResults()[0].Hostname + processID := hosts.GetResults()[0].Id + + hostParams := &GetHostLogsParams{ + GroupID: config.GroupID, + HostName: *hostName, + LogName: "mongodb", + } + // Get logs for the first host in the list + err = getHostLogs(ctx, sdk, hostParams) + if err != nil { + log.Fatalf("Error getting host logs: %v", err) + } + // Get metrics for one disk on the first host in the list + hostMetricParams := HostMetricParams{ + GroupID: config.GroupID, + ProcessID: *processID, + Granularity: admin.PtrString("PT1M"), + Period: admin.PtrString("PT10H"), + } + // Get metrics for the first host in the list + err = getHostMetrics(ctx, sdk, hostMetricParams) + if err != nil { + log.Fatalf("Error getting host metrics: %v", err) + } + + clusterMetricParams := ClusterMetricParams{ + GroupID: config.GroupID, + ProcessID: *processID, + PartitionName: "data", + Period: admin.PtrString("P1D"), + M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, + } + err = getClusterMetrics(ctx, sdk, clusterMetricParams) + if err != nil { + log.Fatalf("Error getting host metrics: %v", err) + } +} + +// GetHostLogs +// Download the logs for a specific host in an Atlas project. +// Equivalent to atlas logs download CLI command +// get hostname from the process list for the cluster +// Get /api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz + +func getHostLogs(ctx context.Context, sdk *admin.APIClient, hostParams *GetHostLogsParams) error { + fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) + resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ + GroupId: hostParams.GroupID, + HostName: hostParams.HostName, + LogName: hostParams.LogName, + EndDate: hostParams.EndDate, + StartDate: hostParams.StartDate, + }).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to fetch logs for host %s in group %s: %w (API error: %v)", hostParams.HostName, hostParams.GroupID, err, apiError) + } + return fmt.Errorf("failed to fetch logs for host %s in group %s: %w", hostParams.HostName, hostParams.GroupID, err) + } + defer func() { + if resp != nil { + if closeErr := resp.Close(); closeErr != nil { + log.Printf("Warning: failed to close response body: %v", closeErr) + } + } + }() + // Create log file + logFileName := fmt.Sprintf("logs_%s_%s.log.gz", hostParams.GroupID, hostParams.HostName) + logFile, err := os.Create(logFileName) + if err != nil { + return fmt.Errorf("failed to create log file %s: %w", logFileName, err) + } + defer func(logFile *os.File) { + if logFile != nil { + if err := logFile.Close(); err != nil { + log.Printf("Warning: failed to close log file: %v", err) + } + } + }(logFile) + + writer := logFile + if _, err = io.Copy(writer, resp); err != nil { + return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) + } + fmt.Printf("Logs saved to %s\n", logFileName) + return nil +} + +func getProjectList(ctx context.Context, sdk *admin.APIClient, projectParams *ListProjectsParams) (*admin.PaginatedAtlasGroup, error) { + resp, _, err := sdk.ProjectsApi.ListProjectsWithParams(ctx, + &admin.ListProjectsApiParams{ + ItemsPerPage: projectParams.ItemsPerPage, + IncludeCount: projectParams.IncludeCount, + PageNum: projectParams.PageNum, + }).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("error getting projects: %w (API error: %v)+", err, + apiError.GetDetail()) + } + } + if resp.GetTotalCount() == 0 { + log.Fatal("account should have at least single project") + } + return resp, nil +} + +// GetProcessList +// Get the list of processes for a specific Atlas project. +// Equivalent to atlas processes list CLI command +// PaginatedHostViewAtlas ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() + +func getProcessList(ctx context.Context, sdk *admin.APIClient, processParams *ListAtlasProcessesParams) (*admin.PaginatedHostViewAtlas, error) { + resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcessesWithParams(ctx, + &admin.ListAtlasProcessesApiParams{ + GroupId: processParams.GroupID, + IncludeCount: processParams.IncludeCount, + ItemsPerPage: processParams.ItemsPerPage, + PageNum: processParams.PageNum, + }).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to list processes in group: %s (API error: %v)", err, apiError.GetDetail()) + } + // Debugging only: Remove or log only at the caller level + // fmt.Fprintf(os.Stdout, "Response: %v\n", resp) + } + if resp.GetTotalCount() == 0 { + return nil, fmt.Errorf("no processes found in group %s", processParams.GroupID) + } + return resp, nil +} + +// Return Measurements for One MongoDB Process +// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() +func getHostMetrics(ctx context.Context, sdk *admin.APIClient, metricParams HostMetricParams) error { + resp, r, err := sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, &admin.GetHostMeasurementsApiParams{ + GroupId: metricParams.GroupID, + ProcessId: metricParams.ProcessID, + Granularity: metricParams.Granularity, + M: metricParams.M, + Period: metricParams.Period, + Start: metricParams.Start, + End: metricParams.End, + }).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for process in group: %s (API error: %v)", err, apiError.GetDetail()) + } + } + if resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for process %s in group %s", metricParams.ProcessID, metricParams.GroupID) + } + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) + return nil +} + +// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements +func getClusterMetrics(ctx context.Context, sdk *admin.APIClient, clusterMetricParams ClusterMetricParams) error { + resp, r, err := sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, &admin.GetDiskMeasurementsApiParams{ + GroupId: clusterMetricParams.GroupID, + ProcessId: clusterMetricParams.ProcessID, + PartitionName: clusterMetricParams.PartitionName, + Period: clusterMetricParams.Period, + M: clusterMetricParams.M, + Start: clusterMetricParams.Start, + End: clusterMetricParams.End, + }).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) + } + } + if resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for cluster %s in group %s", clusterMetricParams.ProcessID, clusterMetricParams.GroupID) + } + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) + return nil +} diff --git a/usage-examples/go/admin-sdk/scripts/types.go b/usage-examples/go/admin-sdk/scripts/types.go new file mode 100644 index 0000000..4059855 --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/types.go @@ -0,0 +1,44 @@ +package main + +import "time" + +type ListAtlasProcessesParams struct { + GroupID string `json:"groupId"` + IncludeCount *bool `json:"includeCount,omitempty"` + ItemsPerPage *int `json:"itemsPerPage,omitempty"` + PageNum *int `json:"pageNum,omitempty"` +} + +type GetHostLogsParams struct { + GroupID string `json:"groupId"` + HostName string `json:"hostName"` + LogName string `json:"logName"` + EndDate *int64 `json:"endDate,omitempty"` + StartDate *int64 `json:"startDate,omitempty"` +} + +type ListProjectsParams struct { + GroupID string `json:"groupId"` + ItemsPerPage *int `json:"itemsPerPage,omitempty"` + IncludeCount *bool `json:"includeCount,omitempty"` + PageNum *int `json:"pageNum,omitempty"` +} + +type HostMetricParams struct { + GroupID string `json:"groupId"` + ProcessID string `json:"processId"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics"` + Period *string `json:"period"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} +type ClusterMetricParams struct { + GroupID string `json:"groupId"` + ProcessID string `json:"processId"` + PartitionName string `json:"partitionName"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"period,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} From 6ab8b511c156c53d4d469a8da468bb5face8d15f Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 18 Mar 2025 22:43:43 -0400 Subject: [PATCH 06/22] Refactor to use apiClient interface --- .gitignore | 1 + usage-examples/go/admin-sdk/bluehawk.sh | 9 + .../go/admin-sdk/config/config-example.json | 22 ++ .../go/admin-sdk/config/config.json | 10 +- .../go/admin-sdk/internal/api_client.go | 91 +++++++ usage-examples/go/admin-sdk/internal/auth.go | 54 ++-- .../go/admin-sdk/internal/config_loader.go | 18 +- usage-examples/go/admin-sdk/internal/mocks.go | 30 +++ .../go/admin-sdk/internal/secrets_loader.go | 40 ++- usage-examples/go/admin-sdk/main.go | 20 -- .../go/admin-sdk/scripts/get_hosts.go | 57 ----- .../go/admin-sdk/scripts/get_logs.go | 87 +++++++ .../go/admin-sdk/scripts/get_logs_metrics.go | 227 ----------------- .../go/admin-sdk/scripts/get_metrics.go | 110 ++++++++ .../go/admin-sdk/scripts/pull_logs_metrics.go | 184 -------------- usage-examples/go/admin-sdk/scripts/types.go | 7 +- .../admin-sdk/tests/get_logs_metrics_test.go | 7 + .../go/admin-sdk/tests/logs_test.go | 39 +++ usage-examples/go/admin-sdk/utils/utility.go | 31 +++ .../z_delete_me/DELETE_pull_logs_metrics.go | 186 ++++++++++++++ .../z_delete_me/SCRATCH_pull_logs_metrics.txt | 91 +++++++ .../admin-sdk/z_delete_me/get_logs_metrics.go | 235 ++++++++++++++++++ 22 files changed, 996 insertions(+), 560 deletions(-) create mode 100644 usage-examples/go/admin-sdk/bluehawk.sh create mode 100644 usage-examples/go/admin-sdk/internal/api_client.go create mode 100644 usage-examples/go/admin-sdk/internal/mocks.go delete mode 100644 usage-examples/go/admin-sdk/scripts/get_hosts.go create mode 100644 usage-examples/go/admin-sdk/scripts/get_logs.go delete mode 100644 usage-examples/go/admin-sdk/scripts/get_logs_metrics.go create mode 100644 usage-examples/go/admin-sdk/scripts/get_metrics.go delete mode 100644 usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go create mode 100644 usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go create mode 100644 usage-examples/go/admin-sdk/tests/logs_test.go create mode 100644 usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go create mode 100644 usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt create mode 100644 usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go diff --git a/.gitignore b/.gitignore index 86413d9..3bddd47 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Logs *.log +*.gz # IDE files ## Visual Studio Code files diff --git a/usage-examples/go/admin-sdk/bluehawk.sh b/usage-examples/go/admin-sdk/bluehawk.sh new file mode 100644 index 0000000..d6bd856 --- /dev/null +++ b/usage-examples/go/admin-sdk/bluehawk.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +PROJECT=$(git rev-parse --show-toplevel) +GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/admin-sdk/config:$PROJECT/usage-examples/go/admin-sdk/scripts:$PROJECT/usage-examples/go/admin-sdk/internal:$PROJECT/usage-examples/go/admin-sdk/types +GENERATED_EXAMPLES=$PROJECT/generated-examples/go/admin-sdk + +# Bluehawk Admin Go SDK examples +echo "Bluehawking Admin Go SDK examples" +npx bluehawk snip $GO_SDK_EXAMPLES -o $GENERATED_EXAMPLES diff --git a/usage-examples/go/admin-sdk/config/config-example.json b/usage-examples/go/admin-sdk/config/config-example.json index 6bcf8b8..613021b 100644 --- a/usage-examples/go/admin-sdk/config/config-example.json +++ b/usage-examples/go/admin-sdk/config/config-example.json @@ -4,3 +4,25 @@ "PAYING_ORG_ID": "", "ORG_ID": "" } + +# Organization & Project Identifiers +ATLAS_ORG_ID="605ae5b5f78e8f0b7f3f8f23" # Example Org ID +ATLAS_PROJECT_ID="605ae5b5f78e8f0b7f3f8f24" # Also known as Group ID + +# Cluster Information +ATLAS_CLUSTER_NAME="ProductionCluster" + +# Host Information +ATLAS_HOSTNAME="cluster0-shard-00-00.abcde.mongodb.net" +ATLAS_PORT="27017" + +# Process Identifier (Alternative to Hostname + Port) +ATLAS_PROCESS_ID="cluster0-shard-00-00.abcde.mongodb.net:27017" + +# Metrics Query Parameters +ATLAS_METRICS_GRANULARITY="PT1M" # 1-minute intervals +ATLAS_METRICS_PERIOD="PT1H" # Last 1 hour of data + +# Other optional values (timeouts, logging, etc.) +ATLAS_REQUEST_TIMEOUT="30s" +ATLAS_LOG_LEVEL="INFO" diff --git a/usage-examples/go/admin-sdk/config/config.json b/usage-examples/go/admin-sdk/config/config.json index 8d8cc8d..46c9a4d 100644 --- a/usage-examples/go/admin-sdk/config/config.json +++ b/usage-examples/go/admin-sdk/config/config.json @@ -1,7 +1,9 @@ { "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "GROUP_ID": "5f60207f14dfb25d23101102", - "BILL_PAYING_ORG_ID": "5bfda007553855125605a5cf", - "ORG_ID": "5bfda007553855125605a5cf", - "CLUSTER_NAME": "Cluster0" + "ATLAS_ORG_ID": "5bfda007553855125605a5cf", + "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" } diff --git a/usage-examples/go/admin-sdk/internal/api_client.go b/usage-examples/go/admin-sdk/internal/api_client.go new file mode 100644 index 0000000..34585ad --- /dev/null +++ b/usage-examples/go/admin-sdk/internal/api_client.go @@ -0,0 +1,91 @@ +package internal + +import ( + "context" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "net/http" +) + +// HTTPClient is a thin wrapper around admin.APIClient for logs. +type HTTPClient struct { + sdk *admin.APIClient +} + +// NewAtlasClient initializes a new LogsService using admin.APIClient. +func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { + return &HTTPClient{sdk: sdk} +} + +// GetHostLogs fetches logs from MongoDB Atlas. +func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { + resp, r, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + return nil, r, err + } + return resp, nil, nil +} + +func (c *HTTPClient) GetClusterMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { + resp, r, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + return resp, r, err + } + return resp, nil, nil +} + +// +//// OrganizationService provides organization-related methods +//type OrganizationService interface { +// ListOrganizations(ctx context.Context) (*admin.PaginatedOrganization, error) +//} +// +//// ProjectService provides project-related methods +//type ProjectService interface { +// ListProjects(ctx context.Context) (*admin.PaginatedAtlasGroup, error) +// +// GetProcesses(ctx context.Context, params *admin.ListAtlasProcessesApiParams) (*admin.PaginatedHostViewAtlas, error) +//} +// +//// ClusterService provides cluster-related methods +//type ClusterService interface { +// ListClusters(ctx context.Context) (*admin.PaginatedOrgGroup, error) +//} +// +//// LogsService provides log retrieval methods +//type LogsService interface { +// GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) +// +//} +// +//type MetricsService interface { +// GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *admin.APIResponse, error) +// +// GetClusterMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) +// +// +//// AtlasClient combines all services into a single interface +//type AtlasClient interface { +// OrganizationService +// ProjectService +// ClusterService +// LogsService +// MetricsService +//} +// +//// HTTPAtlasClient is the concrete implementation of AtlasClient. +//type HTTPAtlasClient struct { +// sdk *admin.APIClient +//} +// +//func NewAtlasClient(sdk *admin.APIClient) *HTTPAtlasClient { +// return &HTTPAtlasClient{sdk: sdk} +//} diff --git a/usage-examples/go/admin-sdk/internal/auth.go b/usage-examples/go/admin-sdk/internal/auth.go index 4e413a6..cb658c9 100644 --- a/usage-examples/go/admin-sdk/internal/auth.go +++ b/usage-examples/go/admin-sdk/internal/auth.go @@ -4,28 +4,23 @@ import ( "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "os" + "log" ) -// CreateAtlasClient initializes and returns an authenticated Atlas API client. -func CreateAtlasClient() (*admin.APIClient, *Secrets, *Config, error) { +// CreateAtlasClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials. +func CreateAtlasClient() (*HTTPClient, *Secrets, *Config, error) { // Load secrets secrets, err := LoadSecrets() if err != nil { return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } else { - fmt.Println("Secrets loaded successfully") } - // Print loaded secrets for debugging - fmt.Printf("Loaded Secrets: %+v\n", secrets) - // Check for missing credentials - if secrets.ClientID == "" || secrets.ClientSecret == "" { + if secrets.ServiceAccountID == "" || secrets.ServiceAccountSecret == "" { return nil, nil, nil, fmt.Errorf("missing Atlas client credentials") } - fmt.Println("Client credentials are present") // Load configuration config, err := LoadConfig("config/config.json") @@ -34,42 +29,27 @@ func CreateAtlasClient() (*admin.APIClient, *Secrets, *Config, error) { } // Determine base URL - host := config.BaseURL - if host == "" { - host = os.Getenv("ATLAS_BASE_URL") + baseURL := config.AtlasBaseURL + if baseURL == "" { + baseURL = "https://cloud.mongodb.com" } - if host == "" { - host = "https://cloud.mongodb.com" + + // Check if ProcessID or Hostname:Port are set + if config.AtlasProcessID == "" || config.AtlasHostName == "" && config.AtlasPort == "" { + log.Fatal("Either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") } - fmt.Println("Using Atlas Base URL:", host) - // Initialize API client + // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() sdk, err := admin.NewClient( - admin.UseBaseURL(host), - admin.UseOAuthAuth(ctx, secrets.ClientID, secrets.ClientSecret), + admin.UseBaseURL(baseURL), + admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), ) if err != nil { return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) } - fmt.Println("SDK client created successfully") - // Determine org ID - orgID := config.OrgID - if orgID == "" { - orgID = os.Getenv("ATLAS_ORG_ID") - } - if orgID == "" { - orgs, _, err := sdk.OrganizationsApi.ListOrganizations(ctx).Execute() - if err != nil { - return nil, nil, nil, fmt.Errorf("error listing organizations: %w", err) - } - if orgs.GetTotalCount() == 0 { - return nil, nil, nil, fmt.Errorf("no organizations found") - } - orgID = orgs.GetResults()[0].GetId() - fmt.Printf("Using organization %s\n", orgID) - } + client := NewAtlasClient(sdk) - return sdk, secrets, config, nil + return client, secrets, config, nil } diff --git a/usage-examples/go/admin-sdk/internal/config_loader.go b/usage-examples/go/admin-sdk/internal/config_loader.go index b52fa82..ec6f622 100644 --- a/usage-examples/go/admin-sdk/internal/config_loader.go +++ b/usage-examples/go/admin-sdk/internal/config_loader.go @@ -11,10 +11,13 @@ used in projects with multiple configs for different environments */ type Config struct { - BaseURL string `json:"ATLAS_BASE_URL"` - GroupID string `json:"GROUP_ID"` - BillPayingOrgID string `json:"BILL_PAYING_ORG_ID"` - OrgID string `json:"ORG_ID"` + AtlasBaseURL string `json:"ATLAS_BASE_URL"` + AtlasOrgID string `json:"ATLAS_ORG_ID"` + AtlasProjectID string `json:"ATLAS_PROJECT_ID"` + AtlasClusterName string `json:"ATLAS_CLUSTER_NAME"` + AtlasHostName string `json:"ATLAS_HOST_NAME"` + AtlasPort string `json:"ATLAS_PORT"` + AtlasProcessID string `json:"ATLAS_PROCESS_ID"` } //func GetConfigFilePath() string { @@ -32,7 +35,12 @@ func LoadConfig(filePath string) (*Config, error) { if err != nil { return nil, fmt.Errorf("error opening config file: %w", err) } - defer file.Close() + defer func(file *os.File) { + err := file.Close() + if err != nil { + fmt.Println("Error closing file") + } + }(file) var config Config decoder := json.NewDecoder(file) diff --git a/usage-examples/go/admin-sdk/internal/mocks.go b/usage-examples/go/admin-sdk/internal/mocks.go new file mode 100644 index 0000000..0fd12e0 --- /dev/null +++ b/usage-examples/go/admin-sdk/internal/mocks.go @@ -0,0 +1,30 @@ +package internal + +import ( + "context" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "strings" +) + +// Abstract the Atlas API client into an interface to allow for mocking. + +// LogsService is a minimal interface for fetching logs. +type LogsService interface { + GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) +} + +// MockLogsClient is a fake implementation of LogsService for testing. +type MockLogsClient struct { + FakeResponse string + FakeError error +} + +// GetHostLogs returns a fake log response or an error. +func (m *MockLogsClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { + if m.FakeError != nil { + return nil, m.FakeError + } + // Simulate a log file as a string + return io.NopCloser(strings.NewReader(m.FakeResponse)), nil +} diff --git a/usage-examples/go/admin-sdk/internal/secrets_loader.go b/usage-examples/go/admin-sdk/internal/secrets_loader.go index 34c95f3..d2c53dc 100644 --- a/usage-examples/go/admin-sdk/internal/secrets_loader.go +++ b/usage-examples/go/admin-sdk/internal/secrets_loader.go @@ -8,33 +8,27 @@ import ( // Secrets structure type Secrets struct { - DBUser string `json:"DB_USER"` - DBPassword string `json:"DB_PASSWORD"` - APIKey string `json:"PUBLIC_API_KEY"` - PrivateKey string `json:"PRIVATE_API_KEY"` - ClientID string `json:"ATLAS_CLIENT_ID"` - ClientSecret string `json:"ATLAS_CLIENT_SECRET"` + MongoDBUser string `json:"MONGODB_USER_NAME"` + MongoDBPassword string `json:"MONGODB_PASSWORD"` + AtlasAPIKey string `json:"MONGODB_ATLAS_PUBLIC_API_KEY"` + AtlasAPISecret string `json:"MONGODB_ATLAS_PRIVATE_KEY"` + ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` + ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` } -// LoadEnv loads environment variables from a .env file -func LoadEnv() { - err := godotenv.Load(".env") - if err != nil { - log.Fatalf("Error loading .env file") - } -} - -// LoadSecrets loads a JSON secrets file into a Secrets struct -// takes a file path as an argument and returns a pointer to a Secrets struct and an error +// LoadSecrets loads environment variables from a .env file into a Secrets struct +// and returns a pointer func LoadSecrets() (*Secrets, error) { - LoadEnv() + if err := godotenv.Load(".env"); err != nil { + log.Println("No .env file found") + } secrets := &Secrets{ - DBUser: os.Getenv("DB_USER"), - DBPassword: os.Getenv("DB_PASSWORD"), - APIKey: os.Getenv("PUBLIC_API_KEY"), - PrivateKey: os.Getenv("PRIVATE_API_KEY"), - ClientID: os.Getenv("ATLAS_CLIENT_ID"), - ClientSecret: os.Getenv("ATLAS_CLIENT_SECRET"), + MongoDBUser: os.Getenv("MONGODB_USER_NAME"), + MongoDBPassword: os.Getenv("MONGODB_PASSWORD"), + AtlasAPIKey: os.Getenv("MONGODB_ATLAS_PUBLIC_KEY"), + AtlasAPISecret: os.Getenv("MONGODB_ATLAS_PRIVATE_KEY"), + ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), + ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), } return secrets, nil } diff --git a/usage-examples/go/admin-sdk/main.go b/usage-examples/go/admin-sdk/main.go index 31120d6..7603f83 100644 --- a/usage-examples/go/admin-sdk/main.go +++ b/usage-examples/go/admin-sdk/main.go @@ -1,21 +1 @@ package testing - -import ( - "admin-sdk/internal" - "fmt" - "os" -) - -func main() { - internal.LoadEnv() - // Verify they are set - fmt.Println("ATLAS_CLIENT_ID:", os.Getenv("ATLAS_CLIENT_ID")) - fmt.Println("ATLAS_CLIENT_SECRET:", os.Getenv("ATLAS_CLIENT_SECRET")) - - // Now you can call LoadSecrets() without needing to manually set env vars - secrets, _ := internal.LoadSecrets() - fmt.Printf("Loaded Secrets: %+v\n", secrets) - - // Now you can call CreateAtlasClient() without needing to manually set env vars - internal.CreateAtlasClient() -} diff --git a/usage-examples/go/admin-sdk/scripts/get_hosts.go b/usage-examples/go/admin-sdk/scripts/get_hosts.go deleted file mode 100644 index 8bcfcf7..0000000 --- a/usage-examples/go/admin-sdk/scripts/get_hosts.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "os" -) - -// GetHostNameFromID retrieves the hostname of a process in an Atlas project. - -func GetHostName(ctx context.Context, sdk *admin.APIClient, groupId string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { - resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) - apiError, ok := admin.AsError(err) - if ok { - fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) - } - // response from `ListAtlasProcesses`: PaginatedHostViewAtlas - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) - } - - return resp, nil -} - -//func getHostFromID(ctx context.Context, sdk *admin.APIClient, groupId, processId string) (string, error) { -// resp, r, err := sdk.MonitoringAndLogsApi.GetAtlasProcess(ctx, groupId, processId).Execute() -// if err != nil { -// fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetProcess`: %v (%v)\n", err, r) -// apiError, ok := admin.AsError(err) -// if ok { -// fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) -// } -// // response from `GetProcess`: Process -// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetProcess`: %v (%v)\n", resp, r) -// } -// return resp.GetHostname(), nil -//} -// -//func main() { -// -// // Initialize Atlas client -// sdk, config, err := internal.CreateAtlasClient() -// if err != nil { -// fmt.Printf("failed to create Atlas client: %v\n", err) -// } -// -// // Get host name -// hostName, err := ListProcesses(context.Background(), sdk, config.GroupID) -// if err != nil { -// fmt.Printf("failed to get host name: %v\n", err) -// return -// } -// -// fmt.Println("Host name:", hostName) -//} diff --git a/usage-examples/go/admin-sdk/scripts/get_logs.go b/usage-examples/go/admin-sdk/scripts/get_logs.go new file mode 100644 index 0000000..0d0616c --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/get_logs.go @@ -0,0 +1,87 @@ +package main + +import ( + "admin-sdk/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" +) + +// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. + +func main() { + ctx := context.Background() + + client, _, config, err := internal.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &GetHostLogsParams{ + GroupID: config.AtlasProjectID, + HostName: config.AtlasHostName, + LogName: "mongodb", // valid values: "mongodb" or "mongos" + } + + if err := getHostLogs(ctx, *client, params); err != nil { + log.Fatalf("Error fetching host logs: %v", err) + } +} + +type GetHostLogsParams struct { + GroupID string `json:"groupId"` // GroupID == ProjectID + HostName string `json:"hostName"` + LogName string `json:"logName"` + EndDate *int64 `json:"endDate,omitempty"` + StartDate *int64 `json:"startDate,omitempty"` +} + +func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { + fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) + + // Create request params + params := &admin.GetHostLogsApiParams{ + GroupId: hostParams.GroupID, + HostName: hostParams.HostName, + LogName: hostParams.LogName, + StartDate: hostParams.StartDate, + EndDate: hostParams.EndDate, + } + + // Call the new GetHostLogs method + resp, err := client.GetHostLogs(ctx, params) + if err != nil { + return fmt.Errorf("failed to fetch logs for host %s in project %s: %w", hostParams.HostName, hostParams.GroupID, err) + } + defer func() { + if resp != nil { + if closeErr := resp.Close(); closeErr != nil { + log.Printf("Warning: failed to close response body: %v", closeErr) + } + } + }() + + // Create log file with a .gz extension + logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) + logFile, err := os.Create(logFileName) + if err != nil { + return fmt.Errorf("failed to create log file: %w", err) + } + defer func(logFile *os.File) { + if logFile != nil { + if err := logFile.Close(); err != nil { + log.Printf("Warning: failed to close log file: %v", err) + } + } + }(logFile) + + // Write logs to file + if _, err = io.Copy(logFile, resp); err != nil { + return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) + } + fmt.Printf("Logs saved to %s\n", logFileName) + return nil +} diff --git a/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go deleted file mode 100644 index ae6d271..0000000 --- a/usage-examples/go/admin-sdk/scripts/get_logs_metrics.go +++ /dev/null @@ -1,227 +0,0 @@ -package main - -import ( - "admin-sdk/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" -) - -func main() { - ctx := context.TODO() - - sdk, _, config, err := internal.CreateAtlasClient() - if err != nil { - log.Fatalf("Error creating Atlas client: %v", err) - } - - // Get the list of projects to retrieve the group ID - projectParams := &ListProjectsParams{ - GroupID: config.GroupID, - ItemsPerPage: admin.PtrInt(1), - IncludeCount: admin.PtrBool(true), - PageNum: admin.PtrInt(1), - } - projects, err := getProjectList(ctx, sdk, projectParams) - if err != nil { - log.Fatalf("Error getting projects: %v", err) - } - projectId := projects.GetResults()[0].Id - - if config.GroupID == "" { - config.GroupID = *projectId - } - - processParams := &ListAtlasProcessesParams{ - GroupID: config.GroupID, - IncludeCount: admin.PtrBool(true), - ItemsPerPage: admin.PtrInt(1), - PageNum: admin.PtrInt(1), - } - hosts, err := getProcessList(ctx, sdk, processParams) - if err != nil { - log.Fatalf("Error getting processes: %v", err) - } - hostName := hosts.GetResults()[0].Hostname - processID := hosts.GetResults()[0].Id - - hostParams := &GetHostLogsParams{ - GroupID: config.GroupID, - HostName: *hostName, - LogName: "mongodb", - } - // Get logs for the first host in the list - err = getHostLogs(ctx, sdk, hostParams) - if err != nil { - log.Fatalf("Error getting host logs: %v", err) - } - // Get metrics for one disk on the first host in the list - hostMetricParams := HostMetricParams{ - GroupID: config.GroupID, - ProcessID: *processID, - Granularity: admin.PtrString("PT1M"), - Period: admin.PtrString("PT10H"), - } - // Get metrics for the first host in the list - err = getHostMetrics(ctx, sdk, hostMetricParams) - if err != nil { - log.Fatalf("Error getting host metrics: %v", err) - } - - clusterMetricParams := ClusterMetricParams{ - GroupID: config.GroupID, - ProcessID: *processID, - PartitionName: "data", - Period: admin.PtrString("P1D"), - M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, - } - err = getClusterMetrics(ctx, sdk, clusterMetricParams) - if err != nil { - log.Fatalf("Error getting host metrics: %v", err) - } -} - -// GetHostLogs -// Download the logs for a specific host in an Atlas project. -// Equivalent to atlas logs download CLI command -// get hostname from the process list for the cluster -// Get /api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz - -func getHostLogs(ctx context.Context, sdk *admin.APIClient, hostParams *GetHostLogsParams) error { - fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) - resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ - GroupId: hostParams.GroupID, - HostName: hostParams.HostName, - LogName: hostParams.LogName, - EndDate: hostParams.EndDate, - StartDate: hostParams.StartDate, - }).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to fetch logs for host %s in group %s: %w (API error: %v)", hostParams.HostName, hostParams.GroupID, err, apiError) - } - return fmt.Errorf("failed to fetch logs for host %s in group %s: %w", hostParams.HostName, hostParams.GroupID, err) - } - defer func() { - if resp != nil { - if closeErr := resp.Close(); closeErr != nil { - log.Printf("Warning: failed to close response body: %v", closeErr) - } - } - }() - // Create log file - logFileName := fmt.Sprintf("logs_%s_%s.log.gz", hostParams.GroupID, hostParams.HostName) - logFile, err := os.Create(logFileName) - if err != nil { - return fmt.Errorf("failed to create log file %s: %w", logFileName, err) - } - defer func(logFile *os.File) { - if logFile != nil { - if err := logFile.Close(); err != nil { - log.Printf("Warning: failed to close log file: %v", err) - } - } - }(logFile) - - writer := logFile - if _, err = io.Copy(writer, resp); err != nil { - return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) - } - fmt.Printf("Logs saved to %s\n", logFileName) - return nil -} - -func getProjectList(ctx context.Context, sdk *admin.APIClient, projectParams *ListProjectsParams) (*admin.PaginatedAtlasGroup, error) { - resp, _, err := sdk.ProjectsApi.ListProjectsWithParams(ctx, - &admin.ListProjectsApiParams{ - ItemsPerPage: projectParams.ItemsPerPage, - IncludeCount: projectParams.IncludeCount, - PageNum: projectParams.PageNum, - }).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("error getting projects: %w (API error: %v)+", err, - apiError.GetDetail()) - } - } - if resp.GetTotalCount() == 0 { - log.Fatal("account should have at least single project") - } - return resp, nil -} - -// GetProcessList -// Get the list of processes for a specific Atlas project. -// Equivalent to atlas processes list CLI command -// PaginatedHostViewAtlas ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() - -func getProcessList(ctx context.Context, sdk *admin.APIClient, processParams *ListAtlasProcessesParams) (*admin.PaginatedHostViewAtlas, error) { - resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcessesWithParams(ctx, - &admin.ListAtlasProcessesApiParams{ - GroupId: processParams.GroupID, - IncludeCount: processParams.IncludeCount, - ItemsPerPage: processParams.ItemsPerPage, - PageNum: processParams.PageNum, - }).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to list processes in group: %s (API error: %v)", err, apiError.GetDetail()) - } - // Debugging only: Remove or log only at the caller level - // fmt.Fprintf(os.Stdout, "Response: %v\n", resp) - } - if resp.GetTotalCount() == 0 { - return nil, fmt.Errorf("no processes found in group %s", processParams.GroupID) - } - return resp, nil -} - -// Return Measurements for One MongoDB Process -// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() -func getHostMetrics(ctx context.Context, sdk *admin.APIClient, metricParams HostMetricParams) error { - resp, r, err := sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, &admin.GetHostMeasurementsApiParams{ - GroupId: metricParams.GroupID, - ProcessId: metricParams.ProcessID, - Granularity: metricParams.Granularity, - M: metricParams.M, - Period: metricParams.Period, - Start: metricParams.Start, - End: metricParams.End, - }).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for process in group: %s (API error: %v)", err, apiError.GetDetail()) - } - } - if resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for process %s in group %s", metricParams.ProcessID, metricParams.GroupID) - } - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) - return nil -} - -// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements -func getClusterMetrics(ctx context.Context, sdk *admin.APIClient, clusterMetricParams ClusterMetricParams) error { - resp, r, err := sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, &admin.GetDiskMeasurementsApiParams{ - GroupId: clusterMetricParams.GroupID, - ProcessId: clusterMetricParams.ProcessID, - PartitionName: clusterMetricParams.PartitionName, - Period: clusterMetricParams.Period, - M: clusterMetricParams.M, - Start: clusterMetricParams.Start, - End: clusterMetricParams.End, - }).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) - } - } - if resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for cluster %s in group %s", clusterMetricParams.ProcessID, clusterMetricParams.GroupID) - } - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) - return nil -} diff --git a/usage-examples/go/admin-sdk/scripts/get_metrics.go b/usage-examples/go/admin-sdk/scripts/get_metrics.go new file mode 100644 index 0000000..151ad7f --- /dev/null +++ b/usage-examples/go/admin-sdk/scripts/get_metrics.go @@ -0,0 +1,110 @@ +package main + +import ( + "admin-sdk/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "os" + "time" +) + +func main() { + ctx := context.Background() + client, _, config, err := internal.CreateAtlasClient() + if err != nil { + fmt.Printf("Failed to create Atlas client: %v", err) + } + + processID := admin.PtrString(config.AtlasHostName + config.AtlasPort) + if config.AtlasProcessID == "" { + config.AtlasProcessID = *processID + } + + getProcessMetricParams := &GetProcessMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: *processID, + Granularity: admin.PtrString("PT1M"), + Period: admin.PtrString("PT10H"), + } + err = getProcessMetrics(ctx, client, getProcessMetricParams) + if err != nil { + fmt.Printf("Error fetching process metrics: %v", err) + } +} + +type GetProcessMetricParams struct { + GroupID string `json:"groupId"` + ProcessID string `json:"processId"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics"` + Period *string `json:"period"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +// Return Measurements for One MongoDB Process +// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() +func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { + fmt.Printf("Fetching metrics for project %s", hostParams.GroupID) + + params := &admin.GetHostMeasurementsApiParams{ + GroupId: hostParams.GroupID, + ProcessId: hostParams.ProcessID, + Granularity: hostParams.Granularity, + M: hostParams.M, + Period: hostParams.Period, + Start: hostParams.Start, + End: hostParams.End, + } + + resp, r, err := client.GetProcessMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + } + if resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for process %s in group %s", params.ProcessId, params.GroupId) + } + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) + return nil +} + +type GetDiskMetricParams struct { + GroupID string `json:"groupId"` + ProcessID string `json:"processId"` + PartitionName string `json:"partitionName"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"period,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements +func getClusterMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) { + + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: diskParams.GroupID, + ProcessId: diskParams.ProcessID, + PartitionName: diskParams.PartitionName, + M: diskParams.M, + Period: diskParams.Period, + Start: diskParams.Start, + End: diskParams.End, + } + + resp, r, err := client.GetClusterMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, nil, fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) + } + } + + if resp.HasMeasurements() == false { + return nil, nil, fmt.Errorf("no measurements found for cluster %s in group %s", diskParams.ProcessID, diskParams.GroupID) + } + fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) + return nil, nil, nil + +} diff --git a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go b/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go deleted file mode 100644 index 652900a..0000000 --- a/usage-examples/go/admin-sdk/scripts/pull_logs_metrics.go +++ /dev/null @@ -1,184 +0,0 @@ -package main - -import ( - "admin-sdk/internal" - "admin-sdk/utils" - "context" - "flag" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" - "time" -) - -//type Metric struct { -// processID string -// groupID string -// granularity string -// metrics []string -// period *string -// start *time.Time -// end *time.Time -//} - -func main() { - ctx := context.Background() - - // CLI Flags - projectID := flag.String("project", "", "Atlas project ID") - logName := flag.String("log", "mongodb", "Log name to fetch") - interval := flag.Int("interval", 0, "Fetch interval in minutes (0 for one-time run)") - // granularity := flag.String("granularity", "PT1M", "Granularity of the metrics") - // metrics := flag.String("metrics", "", "Comma-separated list of metrics to fetch") - flag.Parse() - - // Load Configuration and Authenticate - sdk, secrets, config, err := internal.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Override config values with CLI flags if provided - cfgProjectID := utils.FirstNonEmpty(*projectID, config.GroupID) - cfgLogName := utils.FirstNonEmpty(*logName, "mongodb") - cfgInterval := utils.FirstNonZero(*interval, 0) - // cfgMetrics := utils.FirstNonEmpty(*metrics, "") - // cfgGranularity := utils.FirstNonEmpty(*granularity, "") - - // Ensure required values are set - if cfgProjectID == "" { - log.Fatal("Project ID is required (pass --project flag or set GROUP_ID in config)") - } - //metrics := []string{"SYSTEM"} - //measurement := []string{""} - granularity := "PT1M" - period := "PT10H" - //metrics := []String - //if metrics == "" { - // metrics = strings.Split(*metrics, ",") - //} - //if cfgGranularity == "" { - // cfgGranularity = *granularity - //} - fmt.Println("DEBUG: Calling ListAtlasProcesses with GroupID:", cfgProjectID) - fmt.Printf("DEBUG: SDK Config: %+v\n", sdk) - fmt.Println("DEBUG: Using ClientID:", secrets.ClientID) - fmt.Println("DEBUG: Using ClientSecret Length:", len(secrets.ClientSecret)) - - // Fetch all processes in the project to get hostnames - processes, err := fetchProcesses(ctx, sdk, cfgProjectID, false, 100, 1) - if err != nil { - log.Fatalf("Failed to fetch processes: %v", err) - } - - // Extract host names and process IDs from the response - var processIDs []string - var hostNames []string - if processes.Results != nil { - for _, process := range *processes.Results { - if process.Id != nil { - processIDs = append(processIDs, *process.Id) - } - if process.Hostname != nil { - hostNames = append(hostNames, *process.Hostname) - } - } - } else { - log.Fatal("No processes found in the project") - } - - // Loop through each host and fetch logs & metrics - for { - for i := range processIDs { - if err := fetchHostLogs(ctx, sdk, cfgProjectID, hostNames[i], cfgLogName); err != nil { - log.Printf("Error fetching logs for %s: %v", processIDs[i], err) - } - - if err := fetchHostMetrics(ctx, sdk, cfgProjectID, processIDs[i], granularity, period); err != nil { - log.Printf("Error fetching metrics for %s: %v", processIDs[i], err) - } - } - - if cfgInterval == 0 { - break - } - time.Sleep(time.Duration(cfgInterval) * time.Minute) - } -} - -// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz -func fetchHostLogs(ctx context.Context, sdk *admin.APIClient, groupID, hostName, logName string) error { - fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", groupID, hostName, logName) - - req := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName) - fmt.Println("DEBUG: Generated Fetch Logs API request:", req) - - resp, _, err := req.Execute() - //resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName).Execute() - //dk.MonitoringAndLogsAPI.GetHostLogs(ctx, groupID, hostName, logName).Execute() - if err != nil { - return fmt.Errorf("failed to get logs: %w", err) - } - defer resp.Close() - - logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", groupID, hostName)) - if err != nil { - return fmt.Errorf("failed to create log file: %w", err) - } - defer logFile.Close() - - _, err = io.Copy(logFile, resp) - if err != nil { - return fmt.Errorf("failed to save logs: %w", err) - } - fmt.Println("Logs saved.") - - return nil -} - -//https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/processes/{processId}/measurements - -func fetchHostMetrics(ctx context.Context, sdk *admin.APIClient, groupID, processID, granularity, period string) error { - //fmt.Printf("Fetching metrics for project %s ...\n\n", groupID) - fmt.Printf("DEBUG: Fetching metrics for GroupID: %s, ProcessID: %s, Granularity: %s\n", groupID, processID, granularity, period) - // Simulate request construction - req := sdk.MonitoringAndLogsApi.GetHostMeasurements(ctx, groupID, processID). - Granularity(granularity).Period(period) - - fmt.Println("DEBUG: Generated API request:", req) - - resp, r, err := req.Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GetMeasurements`: %v (%v)\n", err, r) - return err - } - //resp, r, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, groupID, processID).Granularity(granularity).Metrics(metrics).Execute() - //if err != nil { - // fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", err, r) - // apiError, ok := admin.AsError(err) - // if ok { - // fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) - // } - //} - // response from `GetMeasurements`: MeasurementsNonIndex - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", resp, r) - return nil -} - -// GetHostNameFromID retrieves the hostname of a process in an Atlas project. - -func fetchProcesses(ctx context.Context, sdk *admin.APIClient, groupID string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { - resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupID).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) - apiError, ok := admin.AsError(err) - if ok { - fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) - } - // response from `ListAtlasProcesses`: PaginatedHostViewAtlas - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) - } - return resp, nil -} diff --git a/usage-examples/go/admin-sdk/scripts/types.go b/usage-examples/go/admin-sdk/scripts/types.go index 4059855..e726c26 100644 --- a/usage-examples/go/admin-sdk/scripts/types.go +++ b/usage-examples/go/admin-sdk/scripts/types.go @@ -1,3 +1,4 @@ +// :snippet-start: script-structs package main import "time" @@ -9,7 +10,7 @@ type ListAtlasProcessesParams struct { PageNum *int `json:"pageNum,omitempty"` } -type GetHostLogsParams struct { +type Z_GetHostLogsParams struct { GroupID string `json:"groupId"` HostName string `json:"hostName"` LogName string `json:"logName"` @@ -24,7 +25,7 @@ type ListProjectsParams struct { PageNum *int `json:"pageNum,omitempty"` } -type HostMetricParams struct { +type Z_HostMetricParams struct { GroupID string `json:"groupId"` ProcessID string `json:"processId"` Granularity *string `json:"granularity"` @@ -33,7 +34,7 @@ type HostMetricParams struct { Start *time.Time `json:"start,omitempty"` End *time.Time `json:"end,omitempty"` } -type ClusterMetricParams struct { +type Z_ClusterMetricParams struct { GroupID string `json:"groupId"` ProcessID string `json:"processId"` PartitionName string `json:"partitionName"` diff --git a/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go b/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go new file mode 100644 index 0000000..aa107c0 --- /dev/null +++ b/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go @@ -0,0 +1,7 @@ +package tests + +//func TestExample(t *testing.T) { +// notMain.ExampleMain(t) +//} + +// interface apiclient > stubbed response diff --git a/usage-examples/go/admin-sdk/tests/logs_test.go b/usage-examples/go/admin-sdk/tests/logs_test.go new file mode 100644 index 0000000..80fb4dc --- /dev/null +++ b/usage-examples/go/admin-sdk/tests/logs_test.go @@ -0,0 +1,39 @@ +package tests + +//import ( +// "context" +// "errors" +// "myapp/internal" +// "myapp/scripts" +// "testing" +//) +// +//// TestGetHostLogsSuccess ensures logs are fetched successfully. +//func TestGetHostLogsSuccess(t *testing.T) { +// ctx := context.Background() +// +// // Mock client returns fake log data +// mockClient := &internal.MockLogsClient{ +// FakeResponse: "Test log entry\n", +// } +// +// err := scripts.GetHostLogs(ctx, mockClient, "123456", "test-host", "mongodb.log") +// if err != nil { +// t.Fatalf("Unexpected error: %v", err) +// } +//} +// +//// TestGetHostLogsFailure simulates an API failure. +//func TestGetHostLogsFailure(t *testing.T) { +// ctx := context.Background() +// +// // Mock client returns an error +// mockClient := &internal.MockLogsClient{ +// FakeError: errors.New("mock API failure"), +// } +// +// err := scripts.GetHostLogs(ctx, mockClient, "123456", "test-host", "mongodb.log") +// if err == nil { +// t.Fatalf("Expected error but got none") +// } +//} diff --git a/usage-examples/go/admin-sdk/utils/utility.go b/usage-examples/go/admin-sdk/utils/utility.go index a90b407..4c246ad 100644 --- a/usage-examples/go/admin-sdk/utils/utility.go +++ b/usage-examples/go/admin-sdk/utils/utility.go @@ -1,5 +1,12 @@ package utils +import ( + "bytes" + "encoding/json" + "fmt" + "io" +) + // Utility functions func FirstNonEmpty(cli, config string) string { if cli != "" { @@ -20,3 +27,27 @@ func FirstNonZero(cli, config int) int { } return config } + +// FormatResponseAsJSON reads an io.ReadCloser, formats it as pretty JSON, and returns it as a string. +func FormatResponseAsJSON(body io.ReadCloser) (string, error) { + if body == nil { + return "", fmt.Errorf("response body is nil") + } + defer body.Close() + + // Read the body into a buffer + buf := new(bytes.Buffer) + _, err := io.Copy(buf, body) + if err != nil { + return "", fmt.Errorf("failed to read response body: %w", err) + } + + // Convert raw response to JSON + var formattedJSON bytes.Buffer + err = json.Indent(&formattedJSON, buf.Bytes(), "", " ") // Pretty-print JSON + if err != nil { + return "", fmt.Errorf("failed to format response as JSON: %w", err) + } + + return formattedJSON.String(), nil +} diff --git a/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go b/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go new file mode 100644 index 0000000..0c84155 --- /dev/null +++ b/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go @@ -0,0 +1,186 @@ +package z_delete_me + +// +//import ( +// "admin-sdk/internal" +// "admin-sdk/utils" +// "context" +// "flag" +// "fmt" +// "go.mongodb.org/atlas-sdk/v20250219001/admin" +// "io" +// "log" +// "os" +// "time" +//) +// +////type Metric struct { +//// processID string +//// groupID string +//// granularity string +//// metrics []string +//// period *string +//// start *time.Time +//// end *time.Time +////} +// +//func main() { +// ctx := context.Background() +// +// // CLI Flags +// projectID := flag.String("project", "", "Atlas project ID") +// logName := flag.String("log", "mongodb", "Log name to fetch") +// interval := flag.Int("interval", 0, "Fetch interval in minutes (0 for one-time run)") +// // granularity := flag.String("granularity", "PT1M", "Granularity of the metrics") +// // metrics := flag.String("metrics", "", "Comma-separated list of metrics to fetch") +// flag.Parse() +// +// // Load Configuration and Authenticate +// sdk, secrets, config, err := internal.CreateAtlasClient() +// if err != nil { +// log.Fatalf("Failed to create Atlas client: %v", err) +// } +// +// // Override config values with CLI flags if provided +// cfgProjectID := utils.FirstNonEmpty(*projectID, config.GroupID) +// cfgLogName := utils.FirstNonEmpty(*logName, "mongodb") +// cfgInterval := utils.FirstNonZero(*interval, 0) +// // cfgMetrics := utils.FirstNonEmpty(*metrics, "") +// // cfgGranularity := utils.FirstNonEmpty(*granularity, "") +// +// // Ensure required values are set +// if cfgProjectID == "" { +// log.Fatal("Project ID is required (pass --project flag or set GROUP_ID in config)") +// } +// //metrics := []string{"SYSTEM"} +// //measurement := []string{""} +// granularity := "PT1M" +// period := "PT10H" +// //metrics := []String +// //if metrics == "" { +// // metrics = strings.Split(*metrics, ",") +// //} +// //if cfgGranularity == "" { +// // cfgGranularity = *granularity +// //} +// fmt.Println("DEBUG: Calling ListAtlasProcesses with GroupID:", cfgProjectID) +// fmt.Printf("DEBUG: SDK Config: %+v\n", sdk) +// fmt.Println("DEBUG: Using ClientID:", secrets.ClientID) +// fmt.Println("DEBUG: Using ClientSecret Length:", len(secrets.ClientSecret)) +// +// // Fetch all processes in the project to get hostnames +// processes, err := fetchProcesses(ctx, sdk, cfgProjectID, false, 100, 1) +// if err != nil { +// log.Fatalf("Failed to fetch processes: %v", err) +// } +// +// // Extract host names and process IDs from the response +// var processIDs []string +// var hostNames []string +// if processes.Results != nil { +// for _, process := range *processes.Results { +// if process.Id != nil { +// processIDs = append(processIDs, *process.Id) +// } +// if process.Hostname != nil { +// hostNames = append(hostNames, *process.Hostname) +// } +// } +// } else { +// log.Fatal("No processes found in the project") +// } +// +// // Loop through each host and fetch logs & metrics +// for { +// for i := range processIDs { +// //if err := fetchHostLogs(ctx, sdk, cfgProjectID, hostNames[i], cfgLogName); err != nil { +// // log.Printf("Error fetching logs for %s: %v", hostNames[i], err) +// //} +// +// if err := fetchHostMetrics(ctx, sdk, cfgProjectID, processIDs[i], granularity, period); err != nil { +// log.Printf("Error fetching metrics for %s: %v", processIDs[i], err) +// } +// } +// +// if cfgInterval == 0 { +// break +// } +// time.Sleep(time.Duration(cfgInterval) * time.Minute) +// } +//} +// +//// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz +//// io.ReadCloser GetHostLogs(ctx, groupId, hostName, logName).EndDate(endDate).StartDate(startDate).Execute() +//func fetchHostLogs(ctx context.Context, sdk *admin.APIClient, groupID, hostName, logName string) error { +// fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", groupID, hostName, logName) +// +// req := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName) +// fmt.Println("DEBUG: Generated Fetch Logs API request:", req) +// +// resp, _, err := req.Execute() +// //resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName).Execute() +// //dk.MonitoringAndLogsAPI.GetHostLogs(ctx, groupID, hostName, logName).Execute() +// if err != nil { +// return fmt.Errorf("failed to get logs: %w", err) +// } +// defer resp.Close() +// +// logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", groupID, hostName)) +// if err != nil { +// return fmt.Errorf("failed to create log file: %w", err) +// } +// defer logFile.Close() +// +// _, err = io.Copy(logFile, resp) +// if err != nil { +// return fmt.Errorf("failed to save logs: %w", err) +// } +// fmt.Println("Logs saved.") +// +// return nil +//} +// +////https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/processes/{processId}/measurements +// +//func fetchHostMetrics(ctx context.Context, sdk *admin.APIClient, groupID, processID, granularity, period string) error { +// //fmt.Printf("Fetching metrics for project %s ...\n\n", groupID) +// fmt.Printf("DEBUG: Fetching metrics for GroupID: %s, ProcessID: %s, Granularity: %s\n", groupID, processID, granularity, period) +// // Simulate request construction +// req := sdk.MonitoringAndLogsApi.GetHostMeasurements(ctx, groupID, processID). +// Granularity(granularity).Period(period) +// +// fmt.Println("DEBUG: Generated API request:", req) +// +// resp, r, err := req.Execute() +// if err != nil { +// fmt.Fprintf(os.Stderr, "Error when calling `GetMeasurements`: %v (%v)\n", err, r) +// return err +// } +// //resp, r, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, groupID, processID).Granularity(granularity).Metrics(metrics).Execute() +// //if err != nil { +// // fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", err, r) +// // apiError, ok := admin.AsError(err) +// // if ok { +// // fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) +// // } +// //} +// // response from `GetMeasurements`: MeasurementsNonIndex +// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", resp, r) +// return nil +//} +// +//// GetHostNameFromID retrieves the hostname of a process in an Atlas project. +// +//func fetchProcesses(ctx context.Context, sdk *admin.APIClient, groupID string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { +// resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupID).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() +// if err != nil { +// fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) +// apiError, ok := admin.AsError(err) +// if ok { +// fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) +// } +// // response from `ListAtlasProcesses`: PaginatedHostViewAtlas +// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) +// } +// return resp, nil +//} diff --git a/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt b/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt new file mode 100644 index 0000000..44c62f6 --- /dev/null +++ b/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt @@ -0,0 +1,91 @@ +package main +// +//import ( +// "admin-sdk/internal" +// "context" +// "io" +// "log" +// "os" +// +// "go.mongodb.org/atlas-sdk/v20250219001/admin" +//) +// +//most enterprises are going to exclusively use the Admin API for both logs and metrics. +//We need a simple script code example that shows how to +//1. pull logs and metrics from our Admin API +//2. that the user could then use to funnel into whatever system they want +// +//This is likely to be a process that needs to be done on a cadence repeatedly, which is why they need a script + +// Retrieves the first project associated with the account +func get + + + +// +//// Retrieves the first project associated with the account +//// takes a context and an Atlas API client as arguments and returns a string +// +//func getFirstProject(ctx context.Context, sdk *admin.APIClient) string { +// projects, _, _ := sdk.ProjectsApi.ListProjectsWithParams(ctx, +// &admin.ListProjectsApiParams{ +// ItemsPerPage: admin.PtrInt(1), +// IncludeCount: admin.PtrBool(true), +// PageNum: admin.PtrInt(1), +// }).Execute() +// //examples.HandleErr(err, response) +// +// if projects.GetTotalCount() == 0 { +// log.Fatal("Account should have at least one project") +// } +// +// return projects.GetResults()[0].GetId() +//} +// +//// The hosts resource defines the mongod and mongos processes in your deployment. +//// Each process is identified by a unique hostname and port combination. +//// Retrieves the first available host in the project +//// takes a context, an Atlas API client, and a project ID as arguments and returns a string +//func getAllHosts(ctx context.Context, sdk *admin.APIClient, projectId string) string { +// //hosts, _, _ := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, projectId).Execute() +// // examples.HandleErr(err, response) +// +// if len(hosts.GetResults()) == 0 { +// log.Fatal("Your cluster should have at least one host. Are you running Atlas M0?") +// } +// +// host := hosts.GetResults()[0].GetHostname() +// return host +//} +// +//// Fetches and prints logs from a given host +//func downloadLogsForHost(ctx context.Context, sdk *admin.APIClient, projectId, host string) { +// params := &admin.GetHostLogsApiParams{ +// GroupId: projectId, +// HostName: host, +// LogName: "mongos", +// } +// +// logs, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() +// //examples.HandleErr(err, response) +// defer logs.Close() +// +// _, err = io.Copy(os.Stdout, logs) +// //examples.HandleErr(err, nil) +//} +// +//func fetchMetricsForHost(ctx context.Context, sdk *admin.APIClient, projectId, host string) { +// +//} +// +//func main() { +// // Initialize SDK Client +// sdk, ctx := internal.CreateAtlasClient() +// +// // Fetch project, host, and logs +// projectId := getFirstProject(ctx, sdk) +// host := getFirstHost(ctx, sdk, projectId) +// fetchAndPrintLogs(ctx, sdk, projectId, host) +//} +// +//// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz diff --git a/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go b/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go new file mode 100644 index 0000000..5f4145d --- /dev/null +++ b/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go @@ -0,0 +1,235 @@ +package z_delete_me + +// +//import ( +// "admin-sdk/internal" +// "admin-sdk/scripts" +// "context" +// "fmt" +// "go.mongodb.org/atlas-sdk/v20250219001/admin" +// "io" +// "log" +// "os" +// "testing" // :remove: +//) +// +//func GetHostLogsAndMetrics(t *testing.T) { +// ctx := context.Background() +// +// sdk, _, config, err := internal.CreateAtlasClient() +// if err != nil { +// log.Fatalf("Error creating Atlas client: %v", err) +// } +// +// // Get the list of projects to retrieve the groupID +// projectParams := &scripts.ListProjectsParams{ +// GroupID: config.AtlasProjectID, +// ItemsPerPage: admin.PtrInt(1), +// IncludeCount: admin.PtrBool(true), +// PageNum: admin.PtrInt(1), +// } +// projects, err := getProjectList(ctx, sdk, projectParams) +// if err != nil { +// log.Fatalf("Error getting projects: %v", err) +// } +// projectId := projects.GetResults()[0].Id +// +// // If groupID is not set in the config, use the retrieved ID +// if config.AtlasProjectID == "" { +// config.AtlasProjectID = *projectId +// } +// +// // Get list of processes +// processParams := &scripts.ListAtlasProcessesParams{ +// GroupID: config.AtlasProjectID, +// IncludeCount: admin.PtrBool(true), +// ItemsPerPage: admin.PtrInt(1), +// PageNum: admin.PtrInt(1), +// } +// hosts, err := getProcessList(ctx, sdk, processParams) +// if err != nil { +// log.Fatalf("Error getting processes: %v", err) +// } +// hostName := hosts.GetResults()[0].Hostname +// processID := hosts.GetResults()[0].Id +// +// hostParams := &scripts.GetHostLogsParams{ +// GroupID: config.AtlasProjectID, +// HostName: *hostName, +// LogName: "mongodb", +// } +// // Get logs for the first host in the list +// err = scripts.getHostLogs(ctx, sdk, hostParams) +// if err != nil { +// log.Fatalf("Error getting host logs: %v", err) +// } +// // Get metrics for one disk on the first host in the list +// hostMetricParams := scripts.HostMetricParams{ +// GroupID: config.AtlasProjectID, +// ProcessID: *processID, +// Granularity: admin.PtrString("PT1M"), +// Period: admin.PtrString("PT10H"), +// } +// // Get metrics for the first host in the list +// err = getHostMetrics(ctx, sdk, hostMetricParams) +// if err != nil { +// log.Fatalf("Error getting host metrics: %v", err) +// } +// +// clusterMetricParams := scripts.ClusterMetricParams{ +// GroupID: config.AtlasProjectID, +// ProcessID: *processID, +// PartitionName: "data", +// Period: admin.PtrString("P1D"), +// M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, +// } +// err = getClusterMetrics(ctx, sdk, clusterMetricParams) +// if err != nil { +// log.Fatalf("Error getting host metrics: %v", err) +// } +//} +// +//// GetHostLogs +//// Download the logs for a specific host in an Atlas project. +//// Equivalent to atlas logs download CLI command +//// get hostname from the process list for the cluster +//// Get /api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz +// +//func getHostLogs(ctx context.Context, sdk *admin.APIClient, hostParams *GetHostLogsParams) error { +// fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) +// resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ +// GroupId: hostParams.GroupID, +// HostName: hostParams.HostName, +// LogName: hostParams.LogName, +// EndDate: hostParams.EndDate, +// StartDate: hostParams.StartDate, +// }).Execute() +// if err != nil { +// if apiError, ok := admin.AsError(err); ok { +// return fmt.Errorf("failed to fetch logs for host %s in group %s: %w (API error: %v)", hostParams.HostName, hostParams.GroupID, err, apiError) +// } +// return fmt.Errorf("failed to fetch logs for host %s in group %s: %w", hostParams.HostName, hostParams.GroupID, err) +// } +// defer func() { +// if resp != nil { +// if closeErr := resp.Close(); closeErr != nil { +// log.Printf("Warning: failed to close response body: %v", closeErr) +// } +// } +// }() +// // Create log file +// logFileName := fmt.Sprintf("logs_%s_%s.log.gz", hostParams.GroupID, hostParams.HostName) +// logFile, err := os.Create(logFileName) +// if err != nil { +// return fmt.Errorf("failed to create log file %s: %w", logFileName, err) +// } +// defer func(logFile *os.File) { +// if logFile != nil { +// if err := logFile.Close(); err != nil { +// log.Printf("Warning: failed to close log file: %v", err) +// } +// } +// }(logFile) +// +// writer := logFile +// if _, err = io.Copy(writer, resp); err != nil { +// return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) +// } +// fmt.Printf("Logs saved to %s\n", logFileName) +// return nil +//} +// +//func getProjectList(ctx context.Context, sdk *admin.APIClient, projectParams *scripts.ListProjectsParams) (*admin.PaginatedAtlasGroup, error) { +// resp, _, err := sdk.ProjectsApi.ListProjectsWithParams(ctx, +// &admin.ListProjectsApiParams{ +// ItemsPerPage: projectParams.ItemsPerPage, +// IncludeCount: projectParams.IncludeCount, +// PageNum: projectParams.PageNum, +// }).Execute() +// if err != nil { +// if apiError, ok := admin.AsError(err); ok { +// return nil, fmt.Errorf("error getting projects: %w (API error: %v)+", err, +// apiError.GetDetail()) +// } +// } +// if resp.GetTotalCount() == 0 { +// log.Fatal("account should have at least single project") +// } +// return resp, nil +//} +// +//// GetProcessList +//// Get the list of processes for a specific Atlas project. +//// Equivalent to atlas processes list CLI command +//// PaginatedHostViewAtlas ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() +// +//func getProcessList(ctx context.Context, sdk *admin.APIClient, processParams *scripts.ListAtlasProcessesParams) (*admin.PaginatedHostViewAtlas, error) { +// resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcessesWithParams(ctx, +// &admin.ListAtlasProcessesApiParams{ +// GroupId: processParams.GroupID, +// IncludeCount: processParams.IncludeCount, +// ItemsPerPage: processParams.ItemsPerPage, +// PageNum: processParams.PageNum, +// }).Execute() +// if err != nil { +// if apiError, ok := admin.AsError(err); ok { +// return nil, fmt.Errorf("failed to list processes in group: %s (API error: %v)", err, apiError.GetDetail()) +// } +// // Debugging only: Remove or log only at the caller level +// // fmt.Fprintf(os.Stdout, "Response: %v\n", resp) +// } +// if resp.GetTotalCount() == 0 { +// return nil, fmt.Errorf("no processes found in group %s", processParams.GroupID) +// } +// return resp, nil +//} +// +//// Return Measurements for One MongoDB Process +//// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() +//func getHostMetrics(ctx context.Context, sdk *admin.APIClient, metricParams scripts.HostMetricParams) error { +// resp, r, err := sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, &admin.GetHostMeasurementsApiParams{ +// GroupId: metricParams.GroupID, +// ProcessId: metricParams.ProcessID, +// Granularity: metricParams.Granularity, +// M: metricParams.M, +// Period: metricParams.Period, +// Start: metricParams.Start, +// End: metricParams.End, +// }).Execute() +// if err != nil { +// if apiError, ok := admin.AsError(err); ok { +// return fmt.Errorf("failed to get measurements for process in group: %s (API error: %v)", err, apiError.GetDetail()) +// } +// } +// if resp.HasMeasurements() == false { +// return fmt.Errorf("no measurements found for process %s in group %s", metricParams.ProcessID, metricParams.GroupID) +// } +// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) +// return nil +//} +// +//// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements +//func getClusterMetrics(ctx context.Context, sdk *admin.APIClient, clusterMetricParams scripts.ClusterMetricParams) error { +// resp, r, err := sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, &admin.GetDiskMeasurementsApiParams{ +// GroupId: clusterMetricParams.GroupID, +// ProcessId: clusterMetricParams.ProcessID, +// PartitionName: clusterMetricParams.PartitionName, +// Period: clusterMetricParams.Period, +// M: clusterMetricParams.M, +// Start: clusterMetricParams.Start, +// End: clusterMetricParams.End, +// }).Execute() +// if err != nil { +// if apiError, ok := admin.AsError(err); ok { +// return fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) +// } +// } +// if resp.HasMeasurements() == false { +// return fmt.Errorf("no measurements found for cluster %s in group %s", clusterMetricParams.ProcessID, clusterMetricParams.GroupID) +// } +// _, err = fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) +// if err != nil { +// return err +// } +// return nil +//} From cd7d7795ba67cfe9dc80b782c0da612667c50ed5 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Wed, 19 Mar 2025 11:02:09 -0400 Subject: [PATCH 07/22] fixing utility functions --- .../get_logs.go => cmd/get_logs/main.go} | 43 ++-- .../go/admin-sdk/cmd/get_metrics/main.go | 141 +++++++++++ .../go/admin-sdk/config/config-example.json | 28 --- .../config.json => configs/config-dev.json} | 0 .../go/admin-sdk/configs/config-prod.json | 9 + .../go/admin-sdk/configs/config.json | 9 + .../go/admin-sdk/internal/api_client.go | 4 +- .../go/admin-sdk/internal/{ => auth}/auth.go | 19 +- .../go/admin-sdk/internal/config_loader.go | 56 +++-- usage-examples/go/admin-sdk/main.go | 1 - .../go/admin-sdk/scripts/get_metrics.go | 110 -------- usage-examples/go/admin-sdk/scripts/types.go | 10 + usage-examples/go/admin-sdk/utils/utility.go | 56 +++-- .../z_delete_me/DELETE_pull_logs_metrics.go | 186 -------------- .../z_delete_me/SCRATCH_pull_logs_metrics.txt | 91 ------- .../admin-sdk/z_delete_me/get_logs_metrics.go | 235 ------------------ 16 files changed, 281 insertions(+), 717 deletions(-) rename usage-examples/go/admin-sdk/{scripts/get_logs.go => cmd/get_logs/main.go} (84%) create mode 100644 usage-examples/go/admin-sdk/cmd/get_metrics/main.go delete mode 100644 usage-examples/go/admin-sdk/config/config-example.json rename usage-examples/go/admin-sdk/{config/config.json => configs/config-dev.json} (100%) create mode 100644 usage-examples/go/admin-sdk/configs/config-prod.json create mode 100644 usage-examples/go/admin-sdk/configs/config.json rename usage-examples/go/admin-sdk/internal/{ => auth}/auth.go (77%) delete mode 100644 usage-examples/go/admin-sdk/main.go delete mode 100644 usage-examples/go/admin-sdk/scripts/get_metrics.go delete mode 100644 usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go delete mode 100644 usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt delete mode 100644 usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go diff --git a/usage-examples/go/admin-sdk/scripts/get_logs.go b/usage-examples/go/admin-sdk/cmd/get_logs/main.go similarity index 84% rename from usage-examples/go/admin-sdk/scripts/get_logs.go rename to usage-examples/go/admin-sdk/cmd/get_logs/main.go index 0d0616c..ba2bb79 100644 --- a/usage-examples/go/admin-sdk/scripts/get_logs.go +++ b/usage-examples/go/admin-sdk/cmd/get_logs/main.go @@ -2,6 +2,8 @@ package main import ( "admin-sdk/internal" + "admin-sdk/internal/auth" + "admin-sdk/utils" "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" @@ -10,26 +12,10 @@ import ( "os" ) -// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. - -func main() { - ctx := context.Background() - - client, _, config, err := internal.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &GetHostLogsParams{ - GroupID: config.AtlasProjectID, - HostName: config.AtlasHostName, - LogName: "mongodb", // valid values: "mongodb" or "mongos" - } - - if err := getHostLogs(ctx, *client, params); err != nil { - log.Fatalf("Error fetching host logs: %v", err) - } -} +const ( + // LogName is the name of the log file to download + LogName = "mongodb" // valid values: "mongodb" or "mongos" +) type GetHostLogsParams struct { GroupID string `json:"groupId"` // GroupID == ProjectID @@ -39,6 +25,7 @@ type GetHostLogsParams struct { StartDate *int64 `json:"startDate,omitempty"` } +// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) @@ -51,7 +38,6 @@ func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *Ge EndDate: hostParams.EndDate, } - // Call the new GetHostLogs method resp, err := client.GetHostLogs(ctx, params) if err != nil { return fmt.Errorf("failed to fetch logs for host %s in project %s: %w", hostParams.HostName, hostParams.GroupID, err) @@ -85,3 +71,18 @@ func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *Ge fmt.Printf("Logs saved to %s\n", logFileName) return nil } + +func main() { + ctx := context.Background() + + client, _, config, err := auth.CreateAtlasClient() + utils.HandleError(err, "Failed to create Atlas client") + + params := &GetHostLogsParams{ + GroupID: config.AtlasProjectID, + HostName: config.AtlasHostName, + LogName: LogName, + } + + utils.HandleError(getHostLogs(ctx, *client, params), "Error fetching host logs") +} diff --git a/usage-examples/go/admin-sdk/cmd/get_metrics/main.go b/usage-examples/go/admin-sdk/cmd/get_metrics/main.go new file mode 100644 index 0000000..b95ade0 --- /dev/null +++ b/usage-examples/go/admin-sdk/cmd/get_metrics/main.go @@ -0,0 +1,141 @@ +package main + +import ( + "admin-sdk/internal" + "admin-sdk/internal/auth" + "admin-sdk/utils" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "time" +) + +const ( + granularity = "P1D" + period = "P1D" + partitionName = "data" + processMetrics = "DB_DATA_SIZE_TOTAL,MAX_SYSTEM_MEMORY_AVAILABLE" + diskMetrics = "DISK_PARTITION_SPACE_FREE, DISK_PARTITION_SPACE_USED" +) + +type GetProcessMetricParams struct { + GroupID string `json:"groupId"` // GroupID == ProjectID + ProcessID string `json:"processId"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics"` + Period *string `json:"period"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +type GetDiskMetricParams struct { + GroupID string `json:"groupId"` + ProcessID string `json:"processId"` + PartitionName string `json:"partitionName"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"period,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +// Fetches metrics for a specified host process in a project +func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { + fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) + + params := &admin.GetHostMeasurementsApiParams{ + GroupId: hostParams.GroupID, + ProcessId: hostParams.ProcessID, + Granularity: hostParams.Granularity, + M: hostParams.M, + Period: hostParams.Period, + Start: hostParams.Start, + End: hostParams.End, + } + + resp, _, err := client.GetProcessMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + + return nil +} + +// Fetch metrics for a specified disk partition in a project +func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { + + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: diskParams.GroupID, + ProcessId: diskParams.ProcessID, + PartitionName: diskParams.PartitionName, + Granularity: diskParams.Granularity, + M: diskParams.M, + Period: diskParams.Period, + Start: diskParams.Start, + End: diskParams.End, + } + + resp, _, err := client.GetDiskMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + + fmt.Println(string(jsonData)) + + return nil +} + +func main() { + ctx := context.Background() + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + fmt.Printf("Failed to create Atlas client: %v", err) + } + + getProcessMetricParams := &GetProcessMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: config.AtlasProcessID, + M: &[]string{processMetrics}, + Granularity: admin.PtrString(granularity), + Period: admin.PtrString(period), + } + err = getProcessMetrics(ctx, *client, getProcessMetricParams) + utils.HandleError(err, "Error fetching host process metrics") + + getDiskMetricParams := &GetDiskMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: config.AtlasProcessID, + PartitionName: partitionName, + M: &[]string{diskMetrics}, + Granularity: admin.PtrString(granularity), + Period: admin.PtrString(period), + } + err = getDiskMetrics(ctx, *client, getDiskMetricParams) + utils.HandleError(err, "Error fetching partition disk metrics") +} diff --git a/usage-examples/go/admin-sdk/config/config-example.json b/usage-examples/go/admin-sdk/config/config-example.json deleted file mode 100644 index 613021b..0000000 --- a/usage-examples/go/admin-sdk/config/config-example.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "BASEURL": "", - "PAYING_ORG_ID": "", - "ORG_ID": "" -} - -# Organization & Project Identifiers -ATLAS_ORG_ID="605ae5b5f78e8f0b7f3f8f23" # Example Org ID -ATLAS_PROJECT_ID="605ae5b5f78e8f0b7f3f8f24" # Also known as Group ID - -# Cluster Information -ATLAS_CLUSTER_NAME="ProductionCluster" - -# Host Information -ATLAS_HOSTNAME="cluster0-shard-00-00.abcde.mongodb.net" -ATLAS_PORT="27017" - -# Process Identifier (Alternative to Hostname + Port) -ATLAS_PROCESS_ID="cluster0-shard-00-00.abcde.mongodb.net:27017" - -# Metrics Query Parameters -ATLAS_METRICS_GRANULARITY="PT1M" # 1-minute intervals -ATLAS_METRICS_PERIOD="PT1H" # Last 1 hour of data - -# Other optional values (timeouts, logging, etc.) -ATLAS_REQUEST_TIMEOUT="30s" -ATLAS_LOG_LEVEL="INFO" diff --git a/usage-examples/go/admin-sdk/config/config.json b/usage-examples/go/admin-sdk/configs/config-dev.json similarity index 100% rename from usage-examples/go/admin-sdk/config/config.json rename to usage-examples/go/admin-sdk/configs/config-dev.json diff --git a/usage-examples/go/admin-sdk/configs/config-prod.json b/usage-examples/go/admin-sdk/configs/config-prod.json new file mode 100644 index 0000000..46c9a4d --- /dev/null +++ b/usage-examples/go/admin-sdk/configs/config-prod.json @@ -0,0 +1,9 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "5bfda007553855125605a5cf", + "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" +} diff --git a/usage-examples/go/admin-sdk/configs/config.json b/usage-examples/go/admin-sdk/configs/config.json new file mode 100644 index 0000000..f35e046 --- /dev/null +++ b/usage-examples/go/admin-sdk/configs/config.json @@ -0,0 +1,9 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "5bfda007553855125605a5cf", + "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017", +} diff --git a/usage-examples/go/admin-sdk/internal/api_client.go b/usage-examples/go/admin-sdk/internal/api_client.go index 34585ad..d00d544 100644 --- a/usage-examples/go/admin-sdk/internal/api_client.go +++ b/usage-examples/go/admin-sdk/internal/api_client.go @@ -34,7 +34,7 @@ func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHos return resp, nil, nil } -func (c *HTTPClient) GetClusterMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { +func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { resp, r, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() if err != nil { return resp, r, err @@ -69,7 +69,7 @@ func (c *HTTPClient) GetClusterMetrics(ctx context.Context, params *admin.GetDis //type MetricsService interface { // GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *admin.APIResponse, error) // -// GetClusterMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) +// GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) // // //// AtlasClient combines all services into a single interface diff --git a/usage-examples/go/admin-sdk/internal/auth.go b/usage-examples/go/admin-sdk/internal/auth/auth.go similarity index 77% rename from usage-examples/go/admin-sdk/internal/auth.go rename to usage-examples/go/admin-sdk/internal/auth/auth.go index cb658c9..76bdbcd 100644 --- a/usage-examples/go/admin-sdk/internal/auth.go +++ b/usage-examples/go/admin-sdk/internal/auth/auth.go @@ -1,6 +1,7 @@ -package internal +package auth import ( + "admin-sdk/internal" "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" @@ -9,10 +10,10 @@ import ( // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. -func CreateAtlasClient() (*HTTPClient, *Secrets, *Config, error) { +func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { // Load secrets - secrets, err := LoadSecrets() + secrets, err := internal.LoadSecrets() if err != nil { return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) } @@ -23,17 +24,11 @@ func CreateAtlasClient() (*HTTPClient, *Secrets, *Config, error) { } // Load configuration - config, err := LoadConfig("config/config.json") + config, err := internal.LoadConfig("configs/config-dev.json") if err != nil { return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) } - // Determine base URL - baseURL := config.AtlasBaseURL - if baseURL == "" { - baseURL = "https://cloud.mongodb.com" - } - // Check if ProcessID or Hostname:Port are set if config.AtlasProcessID == "" || config.AtlasHostName == "" && config.AtlasPort == "" { log.Fatal("Either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") @@ -42,14 +37,14 @@ func CreateAtlasClient() (*HTTPClient, *Secrets, *Config, error) { // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() sdk, err := admin.NewClient( - admin.UseBaseURL(baseURL), + admin.UseBaseURL(config.AtlasBaseURL), admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), ) if err != nil { return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) } - client := NewAtlasClient(sdk) + client := internal.NewAtlasClient(sdk) return client, secrets, config, nil } diff --git a/usage-examples/go/admin-sdk/internal/config_loader.go b/usage-examples/go/admin-sdk/internal/config_loader.go index ec6f622..b68f91e 100644 --- a/usage-examples/go/admin-sdk/internal/config_loader.go +++ b/usage-examples/go/admin-sdk/internal/config_loader.go @@ -1,14 +1,14 @@ package internal import ( + "admin-sdk/utils" "encoding/json" "fmt" "os" + "strings" ) -/* GetConfigFilePath returns the correct config file based on the environment -used in projects with multiple configs for different environments -*/ +var config Config type Config struct { AtlasBaseURL string `json:"ATLAS_BASE_URL"` @@ -18,22 +18,15 @@ type Config struct { AtlasHostName string `json:"ATLAS_HOST_NAME"` AtlasPort string `json:"ATLAS_PORT"` AtlasProcessID string `json:"ATLAS_PROCESS_ID"` + AppEnv string `json:"APP_ENV"` } -//func GetConfigFilePath() string { -// env := os.Getenv("APP_ENV") // "dev", "prod", "staging" -// if env == "" { -// env = "dev" // Default to development -// } -// return fmt.Sprintf("config/config-%s.json", env) -//} - -// LoadConfig loads a JSON config file into a Config struct +// LoadConfig loads a JSON configs file into a Config struct // takes a file path as an argument and returns a pointer to a Config struct and an error func LoadConfig(filePath string) (*Config, error) { file, err := os.Open(filePath) if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) + return nil, fmt.Errorf("error opening configs file: %w", err) } defer func(file *os.File) { err := file.Close() @@ -42,10 +35,43 @@ func LoadConfig(filePath string) (*Config, error) { } }(file) - var config Config decoder := json.NewDecoder(file) if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) + return nil, fmt.Errorf("error decoding configs file: %w", err) } return &config, nil } + +// GetConfigFilePath returns the correct config file based on the environment +func (c *Config) GetConfigFilePath(string) string { + return fmt.Sprintf("configs/config-%s.json") +} + +// SetDefaults sets default values if specified config variables are empty +func (c *Config) SetDefaults() { + if utils.IsEmptyString(c.AtlasBaseURL) { + c.AtlasBaseURL = "https://cloud.mongodb.com" + } + if utils.IsEmptyString(c.AtlasPort) { + c.AtlasPort = "27017" + } + if utils.IsEmptyString(c.AtlasProcessID) && !utils.IsEmptyString(c.AtlasHostName) { + c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort + } + if utils.IsEmptyString(c.AtlasHostName) { + c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] + } + if utils.IsEmptyString(c.AppEnv) { + c.AppEnv = "dev" // Default to development + } +} + +func (c *Config) CheckRequiredFields() error { + if utils.IsEmptyString(c.AtlasOrgID) || utils.IsEmptyString(c.AtlasProjectID) { + return fmt.Errorf("missing required Atlas fields in config file") + } + if utils.IsEmptyString(c.AtlasProcessID) || utils.IsEmptyString(c.AtlasHostName) && utils.IsEmptyString(c.AtlasPort) { + return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") + } + return nil +} diff --git a/usage-examples/go/admin-sdk/main.go b/usage-examples/go/admin-sdk/main.go deleted file mode 100644 index 7603f83..0000000 --- a/usage-examples/go/admin-sdk/main.go +++ /dev/null @@ -1 +0,0 @@ -package testing diff --git a/usage-examples/go/admin-sdk/scripts/get_metrics.go b/usage-examples/go/admin-sdk/scripts/get_metrics.go deleted file mode 100644 index 151ad7f..0000000 --- a/usage-examples/go/admin-sdk/scripts/get_metrics.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "admin-sdk/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "os" - "time" -) - -func main() { - ctx := context.Background() - client, _, config, err := internal.CreateAtlasClient() - if err != nil { - fmt.Printf("Failed to create Atlas client: %v", err) - } - - processID := admin.PtrString(config.AtlasHostName + config.AtlasPort) - if config.AtlasProcessID == "" { - config.AtlasProcessID = *processID - } - - getProcessMetricParams := &GetProcessMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: *processID, - Granularity: admin.PtrString("PT1M"), - Period: admin.PtrString("PT10H"), - } - err = getProcessMetrics(ctx, client, getProcessMetricParams) - if err != nil { - fmt.Printf("Error fetching process metrics: %v", err) - } -} - -type GetProcessMetricParams struct { - GroupID string `json:"groupId"` - ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics"` - Period *string `json:"period"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -// Return Measurements for One MongoDB Process -// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() -func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { - fmt.Printf("Fetching metrics for project %s", hostParams.GroupID) - - params := &admin.GetHostMeasurementsApiParams{ - GroupId: hostParams.GroupID, - ProcessId: hostParams.ProcessID, - Granularity: hostParams.Granularity, - M: hostParams.M, - Period: hostParams.Period, - Start: hostParams.Start, - End: hostParams.End, - } - - resp, r, err := client.GetProcessMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - } - if resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for process %s in group %s", params.ProcessId, params.GroupId) - } - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) - return nil -} - -type GetDiskMetricParams struct { - GroupID string `json:"groupId"` - ProcessID string `json:"processId"` - PartitionName string `json:"partitionName"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"period,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements -func getClusterMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) { - - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: diskParams.GroupID, - ProcessId: diskParams.ProcessID, - PartitionName: diskParams.PartitionName, - M: diskParams.M, - Period: diskParams.Period, - Start: diskParams.Start, - End: diskParams.End, - } - - resp, r, err := client.GetClusterMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, nil, fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) - } - } - - if resp.HasMeasurements() == false { - return nil, nil, fmt.Errorf("no measurements found for cluster %s in group %s", diskParams.ProcessID, diskParams.GroupID) - } - fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) - return nil, nil, nil - -} diff --git a/usage-examples/go/admin-sdk/scripts/types.go b/usage-examples/go/admin-sdk/scripts/types.go index e726c26..1f348e6 100644 --- a/usage-examples/go/admin-sdk/scripts/types.go +++ b/usage-examples/go/admin-sdk/scripts/types.go @@ -43,3 +43,13 @@ type Z_ClusterMetricParams struct { Start *time.Time `json:"start,omitempty"` End *time.Time `json:"end,omitempty"` } + +type Measurement struct { + Name string `json:"name"` + Data []MetricDataPointAtlas `json:"data"` +} + +type MetricDataPointAtlas struct { + Timestamp string `json:"timestamp"` + Value float64 `json:"value"` +} diff --git a/usage-examples/go/admin-sdk/utils/utility.go b/usage-examples/go/admin-sdk/utils/utility.go index 4c246ad..fa8fe5f 100644 --- a/usage-examples/go/admin-sdk/utils/utility.go +++ b/usage-examples/go/admin-sdk/utils/utility.go @@ -5,27 +5,26 @@ import ( "encoding/json" "fmt" "io" + "log" + "os" + "strings" + "time" ) -// Utility functions -func FirstNonEmpty(cli, config string) string { - if cli != "" { - return cli +// LoadEnvWithDefault loads an environment variable or returns a default value if not set. +func LoadEnvWithDefault(key, defaultValue string) string { + value := os.Getenv(key) + if value == "" { + return defaultValue } - return config -} -func FirstNonEmptyArray(cli, config []string) []string { - if len(cli) > 0 { - return cli - } - return config + return value } -func FirstNonZero(cli, config int) int { - if cli != 0 { - return cli +// HandleError logs the error and exits the program. +func HandleError(err error, message string) { + if err != nil { + log.Fatalf("%s: %v", message, err) } - return config } // FormatResponseAsJSON reads an io.ReadCloser, formats it as pretty JSON, and returns it as a string. @@ -33,7 +32,12 @@ func FormatResponseAsJSON(body io.ReadCloser) (string, error) { if body == nil { return "", fmt.Errorf("response body is nil") } - defer body.Close() + defer func(body io.ReadCloser) { + err := body.Close() + if err != nil { + HandleError(err, "Error closing body") + } + }(body) // Read the body into a buffer buf := new(bytes.Buffer) @@ -51,3 +55,23 @@ func FormatResponseAsJSON(body io.ReadCloser) (string, error) { return formattedJSON.String(), nil } + +// IsEmptyString checks if a string is empty or contains only whitespace. +func IsEmptyString(s string) bool { + return strings.TrimSpace(s) == "" +} + +// Retry retries a function up to a specified number of times with a delay between attempts. +func Retry(attempts int, sleep time.Duration, fn func() error) error { + for i := 0; i < attempts; i++ { + if err := fn(); err != nil { + if i >= (attempts - 1) { + return err + } + time.Sleep(sleep) + continue + } + return nil + } + return fmt.Errorf("reached maximum retry attempts") +} diff --git a/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go b/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go deleted file mode 100644 index 0c84155..0000000 --- a/usage-examples/go/admin-sdk/z_delete_me/DELETE_pull_logs_metrics.go +++ /dev/null @@ -1,186 +0,0 @@ -package z_delete_me - -// -//import ( -// "admin-sdk/internal" -// "admin-sdk/utils" -// "context" -// "flag" -// "fmt" -// "go.mongodb.org/atlas-sdk/v20250219001/admin" -// "io" -// "log" -// "os" -// "time" -//) -// -////type Metric struct { -//// processID string -//// groupID string -//// granularity string -//// metrics []string -//// period *string -//// start *time.Time -//// end *time.Time -////} -// -//func main() { -// ctx := context.Background() -// -// // CLI Flags -// projectID := flag.String("project", "", "Atlas project ID") -// logName := flag.String("log", "mongodb", "Log name to fetch") -// interval := flag.Int("interval", 0, "Fetch interval in minutes (0 for one-time run)") -// // granularity := flag.String("granularity", "PT1M", "Granularity of the metrics") -// // metrics := flag.String("metrics", "", "Comma-separated list of metrics to fetch") -// flag.Parse() -// -// // Load Configuration and Authenticate -// sdk, secrets, config, err := internal.CreateAtlasClient() -// if err != nil { -// log.Fatalf("Failed to create Atlas client: %v", err) -// } -// -// // Override config values with CLI flags if provided -// cfgProjectID := utils.FirstNonEmpty(*projectID, config.GroupID) -// cfgLogName := utils.FirstNonEmpty(*logName, "mongodb") -// cfgInterval := utils.FirstNonZero(*interval, 0) -// // cfgMetrics := utils.FirstNonEmpty(*metrics, "") -// // cfgGranularity := utils.FirstNonEmpty(*granularity, "") -// -// // Ensure required values are set -// if cfgProjectID == "" { -// log.Fatal("Project ID is required (pass --project flag or set GROUP_ID in config)") -// } -// //metrics := []string{"SYSTEM"} -// //measurement := []string{""} -// granularity := "PT1M" -// period := "PT10H" -// //metrics := []String -// //if metrics == "" { -// // metrics = strings.Split(*metrics, ",") -// //} -// //if cfgGranularity == "" { -// // cfgGranularity = *granularity -// //} -// fmt.Println("DEBUG: Calling ListAtlasProcesses with GroupID:", cfgProjectID) -// fmt.Printf("DEBUG: SDK Config: %+v\n", sdk) -// fmt.Println("DEBUG: Using ClientID:", secrets.ClientID) -// fmt.Println("DEBUG: Using ClientSecret Length:", len(secrets.ClientSecret)) -// -// // Fetch all processes in the project to get hostnames -// processes, err := fetchProcesses(ctx, sdk, cfgProjectID, false, 100, 1) -// if err != nil { -// log.Fatalf("Failed to fetch processes: %v", err) -// } -// -// // Extract host names and process IDs from the response -// var processIDs []string -// var hostNames []string -// if processes.Results != nil { -// for _, process := range *processes.Results { -// if process.Id != nil { -// processIDs = append(processIDs, *process.Id) -// } -// if process.Hostname != nil { -// hostNames = append(hostNames, *process.Hostname) -// } -// } -// } else { -// log.Fatal("No processes found in the project") -// } -// -// // Loop through each host and fetch logs & metrics -// for { -// for i := range processIDs { -// //if err := fetchHostLogs(ctx, sdk, cfgProjectID, hostNames[i], cfgLogName); err != nil { -// // log.Printf("Error fetching logs for %s: %v", hostNames[i], err) -// //} -// -// if err := fetchHostMetrics(ctx, sdk, cfgProjectID, processIDs[i], granularity, period); err != nil { -// log.Printf("Error fetching metrics for %s: %v", processIDs[i], err) -// } -// } -// -// if cfgInterval == 0 { -// break -// } -// time.Sleep(time.Duration(cfgInterval) * time.Minute) -// } -//} -// -//// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz -//// io.ReadCloser GetHostLogs(ctx, groupId, hostName, logName).EndDate(endDate).StartDate(startDate).Execute() -//func fetchHostLogs(ctx context.Context, sdk *admin.APIClient, groupID, hostName, logName string) error { -// fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", groupID, hostName, logName) -// -// req := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName) -// fmt.Println("DEBUG: Generated Fetch Logs API request:", req) -// -// resp, _, err := req.Execute() -// //resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogs(ctx, groupID, hostName, logName).Execute() -// //dk.MonitoringAndLogsAPI.GetHostLogs(ctx, groupID, hostName, logName).Execute() -// if err != nil { -// return fmt.Errorf("failed to get logs: %w", err) -// } -// defer resp.Close() -// -// logFile, err := os.Create(fmt.Sprintf("logs_%s_%s.log", groupID, hostName)) -// if err != nil { -// return fmt.Errorf("failed to create log file: %w", err) -// } -// defer logFile.Close() -// -// _, err = io.Copy(logFile, resp) -// if err != nil { -// return fmt.Errorf("failed to save logs: %w", err) -// } -// fmt.Println("Logs saved.") -// -// return nil -//} -// -////https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/processes/{processId}/measurements -// -//func fetchHostMetrics(ctx context.Context, sdk *admin.APIClient, groupID, processID, granularity, period string) error { -// //fmt.Printf("Fetching metrics for project %s ...\n\n", groupID) -// fmt.Printf("DEBUG: Fetching metrics for GroupID: %s, ProcessID: %s, Granularity: %s\n", groupID, processID, granularity, period) -// // Simulate request construction -// req := sdk.MonitoringAndLogsApi.GetHostMeasurements(ctx, groupID, processID). -// Granularity(granularity).Period(period) -// -// fmt.Println("DEBUG: Generated API request:", req) -// -// resp, r, err := req.Execute() -// if err != nil { -// fmt.Fprintf(os.Stderr, "Error when calling `GetMeasurements`: %v (%v)\n", err, r) -// return err -// } -// //resp, r, err := sdk.MonitoringAndLogsApi.GetMeasurements(ctx, groupID, processID).Granularity(granularity).Metrics(metrics).Execute() -// //if err != nil { -// // fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", err, r) -// // apiError, ok := admin.AsError(err) -// // if ok { -// // fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) -// // } -// //} -// // response from `GetMeasurements`: MeasurementsNonIndex -// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)\n", resp, r) -// return nil -//} -// -//// GetHostNameFromID retrieves the hostname of a process in an Atlas project. -// -//func fetchProcesses(ctx context.Context, sdk *admin.APIClient, groupID string, includeCount bool, itemsPerPage, pageNum int) (*admin.PaginatedHostViewAtlas, error) { -// resp, r, err := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, groupID).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() -// if err != nil { -// fmt.Fprintf(os.Stderr, "Error when calling `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", err, r) -// apiError, ok := admin.AsError(err) -// if ok { -// fmt.Fprintf(os.Stderr, "API error obj: %v\n", apiError) -// } -// // response from `ListAtlasProcesses`: PaginatedHostViewAtlas -// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.ListAtlasProcesses`: %v (%v)\n", resp, r) -// } -// return resp, nil -//} diff --git a/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt b/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt deleted file mode 100644 index 44c62f6..0000000 --- a/usage-examples/go/admin-sdk/z_delete_me/SCRATCH_pull_logs_metrics.txt +++ /dev/null @@ -1,91 +0,0 @@ -package main -// -//import ( -// "admin-sdk/internal" -// "context" -// "io" -// "log" -// "os" -// -// "go.mongodb.org/atlas-sdk/v20250219001/admin" -//) -// -//most enterprises are going to exclusively use the Admin API for both logs and metrics. -//We need a simple script code example that shows how to -//1. pull logs and metrics from our Admin API -//2. that the user could then use to funnel into whatever system they want -// -//This is likely to be a process that needs to be done on a cadence repeatedly, which is why they need a script - -// Retrieves the first project associated with the account -func get - - - -// -//// Retrieves the first project associated with the account -//// takes a context and an Atlas API client as arguments and returns a string -// -//func getFirstProject(ctx context.Context, sdk *admin.APIClient) string { -// projects, _, _ := sdk.ProjectsApi.ListProjectsWithParams(ctx, -// &admin.ListProjectsApiParams{ -// ItemsPerPage: admin.PtrInt(1), -// IncludeCount: admin.PtrBool(true), -// PageNum: admin.PtrInt(1), -// }).Execute() -// //examples.HandleErr(err, response) -// -// if projects.GetTotalCount() == 0 { -// log.Fatal("Account should have at least one project") -// } -// -// return projects.GetResults()[0].GetId() -//} -// -//// The hosts resource defines the mongod and mongos processes in your deployment. -//// Each process is identified by a unique hostname and port combination. -//// Retrieves the first available host in the project -//// takes a context, an Atlas API client, and a project ID as arguments and returns a string -//func getAllHosts(ctx context.Context, sdk *admin.APIClient, projectId string) string { -// //hosts, _, _ := sdk.MonitoringAndLogsApi.ListAtlasProcesses(ctx, projectId).Execute() -// // examples.HandleErr(err, response) -// -// if len(hosts.GetResults()) == 0 { -// log.Fatal("Your cluster should have at least one host. Are you running Atlas M0?") -// } -// -// host := hosts.GetResults()[0].GetHostname() -// return host -//} -// -//// Fetches and prints logs from a given host -//func downloadLogsForHost(ctx context.Context, sdk *admin.APIClient, projectId, host string) { -// params := &admin.GetHostLogsApiParams{ -// GroupId: projectId, -// HostName: host, -// LogName: "mongos", -// } -// -// logs, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() -// //examples.HandleErr(err, response) -// defer logs.Close() -// -// _, err = io.Copy(os.Stdout, logs) -// //examples.HandleErr(err, nil) -//} -// -//func fetchMetricsForHost(ctx context.Context, sdk *admin.APIClient, projectId, host string) { -// -//} -// -//func main() { -// // Initialize SDK Client -// sdk, ctx := internal.CreateAtlasClient() -// -// // Fetch project, host, and logs -// projectId := getFirstProject(ctx, sdk) -// host := getFirstHost(ctx, sdk, projectId) -// fetchAndPrintLogs(ctx, sdk, projectId, host) -//} -// -//// https://cloud.mongodb.com/api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz diff --git a/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go b/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go deleted file mode 100644 index 5f4145d..0000000 --- a/usage-examples/go/admin-sdk/z_delete_me/get_logs_metrics.go +++ /dev/null @@ -1,235 +0,0 @@ -package z_delete_me - -// -//import ( -// "admin-sdk/internal" -// "admin-sdk/scripts" -// "context" -// "fmt" -// "go.mongodb.org/atlas-sdk/v20250219001/admin" -// "io" -// "log" -// "os" -// "testing" // :remove: -//) -// -//func GetHostLogsAndMetrics(t *testing.T) { -// ctx := context.Background() -// -// sdk, _, config, err := internal.CreateAtlasClient() -// if err != nil { -// log.Fatalf("Error creating Atlas client: %v", err) -// } -// -// // Get the list of projects to retrieve the groupID -// projectParams := &scripts.ListProjectsParams{ -// GroupID: config.AtlasProjectID, -// ItemsPerPage: admin.PtrInt(1), -// IncludeCount: admin.PtrBool(true), -// PageNum: admin.PtrInt(1), -// } -// projects, err := getProjectList(ctx, sdk, projectParams) -// if err != nil { -// log.Fatalf("Error getting projects: %v", err) -// } -// projectId := projects.GetResults()[0].Id -// -// // If groupID is not set in the config, use the retrieved ID -// if config.AtlasProjectID == "" { -// config.AtlasProjectID = *projectId -// } -// -// // Get list of processes -// processParams := &scripts.ListAtlasProcessesParams{ -// GroupID: config.AtlasProjectID, -// IncludeCount: admin.PtrBool(true), -// ItemsPerPage: admin.PtrInt(1), -// PageNum: admin.PtrInt(1), -// } -// hosts, err := getProcessList(ctx, sdk, processParams) -// if err != nil { -// log.Fatalf("Error getting processes: %v", err) -// } -// hostName := hosts.GetResults()[0].Hostname -// processID := hosts.GetResults()[0].Id -// -// hostParams := &scripts.GetHostLogsParams{ -// GroupID: config.AtlasProjectID, -// HostName: *hostName, -// LogName: "mongodb", -// } -// // Get logs for the first host in the list -// err = scripts.getHostLogs(ctx, sdk, hostParams) -// if err != nil { -// log.Fatalf("Error getting host logs: %v", err) -// } -// // Get metrics for one disk on the first host in the list -// hostMetricParams := scripts.HostMetricParams{ -// GroupID: config.AtlasProjectID, -// ProcessID: *processID, -// Granularity: admin.PtrString("PT1M"), -// Period: admin.PtrString("PT10H"), -// } -// // Get metrics for the first host in the list -// err = getHostMetrics(ctx, sdk, hostMetricParams) -// if err != nil { -// log.Fatalf("Error getting host metrics: %v", err) -// } -// -// clusterMetricParams := scripts.ClusterMetricParams{ -// GroupID: config.AtlasProjectID, -// ProcessID: *processID, -// PartitionName: "data", -// Period: admin.PtrString("P1D"), -// M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, -// } -// err = getClusterMetrics(ctx, sdk, clusterMetricParams) -// if err != nil { -// log.Fatalf("Error getting host metrics: %v", err) -// } -//} -// -//// GetHostLogs -//// Download the logs for a specific host in an Atlas project. -//// Equivalent to atlas logs download CLI command -//// get hostname from the process list for the cluster -//// Get /api/atlas/v2/groups/{groupId}/clusters/{hostName}/logs/{logName}.gz -// -//func getHostLogs(ctx context.Context, sdk *admin.APIClient, hostParams *GetHostLogsParams) error { -// fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) -// resp, _, err := sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, &admin.GetHostLogsApiParams{ -// GroupId: hostParams.GroupID, -// HostName: hostParams.HostName, -// LogName: hostParams.LogName, -// EndDate: hostParams.EndDate, -// StartDate: hostParams.StartDate, -// }).Execute() -// if err != nil { -// if apiError, ok := admin.AsError(err); ok { -// return fmt.Errorf("failed to fetch logs for host %s in group %s: %w (API error: %v)", hostParams.HostName, hostParams.GroupID, err, apiError) -// } -// return fmt.Errorf("failed to fetch logs for host %s in group %s: %w", hostParams.HostName, hostParams.GroupID, err) -// } -// defer func() { -// if resp != nil { -// if closeErr := resp.Close(); closeErr != nil { -// log.Printf("Warning: failed to close response body: %v", closeErr) -// } -// } -// }() -// // Create log file -// logFileName := fmt.Sprintf("logs_%s_%s.log.gz", hostParams.GroupID, hostParams.HostName) -// logFile, err := os.Create(logFileName) -// if err != nil { -// return fmt.Errorf("failed to create log file %s: %w", logFileName, err) -// } -// defer func(logFile *os.File) { -// if logFile != nil { -// if err := logFile.Close(); err != nil { -// log.Printf("Warning: failed to close log file: %v", err) -// } -// } -// }(logFile) -// -// writer := logFile -// if _, err = io.Copy(writer, resp); err != nil { -// return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) -// } -// fmt.Printf("Logs saved to %s\n", logFileName) -// return nil -//} -// -//func getProjectList(ctx context.Context, sdk *admin.APIClient, projectParams *scripts.ListProjectsParams) (*admin.PaginatedAtlasGroup, error) { -// resp, _, err := sdk.ProjectsApi.ListProjectsWithParams(ctx, -// &admin.ListProjectsApiParams{ -// ItemsPerPage: projectParams.ItemsPerPage, -// IncludeCount: projectParams.IncludeCount, -// PageNum: projectParams.PageNum, -// }).Execute() -// if err != nil { -// if apiError, ok := admin.AsError(err); ok { -// return nil, fmt.Errorf("error getting projects: %w (API error: %v)+", err, -// apiError.GetDetail()) -// } -// } -// if resp.GetTotalCount() == 0 { -// log.Fatal("account should have at least single project") -// } -// return resp, nil -//} -// -//// GetProcessList -//// Get the list of processes for a specific Atlas project. -//// Equivalent to atlas processes list CLI command -//// PaginatedHostViewAtlas ListAtlasProcesses(ctx, groupId).IncludeCount(includeCount).ItemsPerPage(itemsPerPage).PageNum(pageNum).Execute() -// -//func getProcessList(ctx context.Context, sdk *admin.APIClient, processParams *scripts.ListAtlasProcessesParams) (*admin.PaginatedHostViewAtlas, error) { -// resp, _, err := sdk.MonitoringAndLogsApi.ListAtlasProcessesWithParams(ctx, -// &admin.ListAtlasProcessesApiParams{ -// GroupId: processParams.GroupID, -// IncludeCount: processParams.IncludeCount, -// ItemsPerPage: processParams.ItemsPerPage, -// PageNum: processParams.PageNum, -// }).Execute() -// if err != nil { -// if apiError, ok := admin.AsError(err); ok { -// return nil, fmt.Errorf("failed to list processes in group: %s (API error: %v)", err, apiError.GetDetail()) -// } -// // Debugging only: Remove or log only at the caller level -// // fmt.Fprintf(os.Stdout, "Response: %v\n", resp) -// } -// if resp.GetTotalCount() == 0 { -// return nil, fmt.Errorf("no processes found in group %s", processParams.GroupID) -// } -// return resp, nil -//} -// -//// Return Measurements for One MongoDB Process -//// ApiMeasurementsGeneralViewAtlas GetHostMeasurements(ctx, groupId, processId).Granularity(granularity).M(m).Period(period).Start(start).End(end).Execute() -//func getHostMetrics(ctx context.Context, sdk *admin.APIClient, metricParams scripts.HostMetricParams) error { -// resp, r, err := sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, &admin.GetHostMeasurementsApiParams{ -// GroupId: metricParams.GroupID, -// ProcessId: metricParams.ProcessID, -// Granularity: metricParams.Granularity, -// M: metricParams.M, -// Period: metricParams.Period, -// Start: metricParams.Start, -// End: metricParams.End, -// }).Execute() -// if err != nil { -// if apiError, ok := admin.AsError(err); ok { -// return fmt.Errorf("failed to get measurements for process in group: %s (API error: %v)", err, apiError.GetDetail()) -// } -// } -// if resp.HasMeasurements() == false { -// return fmt.Errorf("no measurements found for process %s in group %s", metricParams.ProcessID, metricParams.GroupID) -// } -// fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetMeasurements`: %v (%v)", resp, r) -// return nil -//} -// -//// Get /api/atlas/v2/groups/{groupId}/processes/{processId}/disks/{partitionName}/measurements -//func getClusterMetrics(ctx context.Context, sdk *admin.APIClient, clusterMetricParams scripts.ClusterMetricParams) error { -// resp, r, err := sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, &admin.GetDiskMeasurementsApiParams{ -// GroupId: clusterMetricParams.GroupID, -// ProcessId: clusterMetricParams.ProcessID, -// PartitionName: clusterMetricParams.PartitionName, -// Period: clusterMetricParams.Period, -// M: clusterMetricParams.M, -// Start: clusterMetricParams.Start, -// End: clusterMetricParams.End, -// }).Execute() -// if err != nil { -// if apiError, ok := admin.AsError(err); ok { -// return fmt.Errorf("failed to get measurements for cluster in group: %s (API error: %v)", err, apiError.GetDetail()) -// } -// } -// if resp.HasMeasurements() == false { -// return fmt.Errorf("no measurements found for cluster %s in group %s", clusterMetricParams.ProcessID, clusterMetricParams.GroupID) -// } -// _, err = fmt.Fprintf(os.Stdout, "Response from `MonitoringAndLogsApi.GetDiskMeasurement`: %v (%v)", resp, r) -// if err != nil { -// return err -// } -// return nil -//} From 79663dc3ba56965e873a7b414a6b24f6e313411e Mon Sep 17 00:00:00 2001 From: cbullinger Date: Wed, 19 Mar 2025 14:15:15 -0400 Subject: [PATCH 08/22] Add finalized mock tests for Monitoring & Logging functions --- .../go/admin-sdk/cmd/get_logs/main.go | 1 - .../go/admin-sdk/cmd/get_metrics/main.go | 17 +- .../go/admin-sdk/configs/config.json | 14 +- usage-examples/go/admin-sdk/go.mod | 4 + usage-examples/go/admin-sdk/go.sum | 2 + .../go/admin-sdk/internal/api_client.go | 61 ++----- .../go/admin-sdk/internal/auth/auth.go | 13 +- .../go/admin-sdk/internal/config_loader.go | 67 ++++--- usage-examples/go/admin-sdk/internal/mocks.go | 43 +++-- .../admin-sdk/tests/get_logs_metrics_test.go | 7 - .../go/admin-sdk/tests/logs_test.go | 39 ---- .../go/admin-sdk/tests/mock_test.go | 170 ++++++++++++++++++ 12 files changed, 267 insertions(+), 171 deletions(-) delete mode 100644 usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go delete mode 100644 usage-examples/go/admin-sdk/tests/logs_test.go create mode 100644 usage-examples/go/admin-sdk/tests/mock_test.go diff --git a/usage-examples/go/admin-sdk/cmd/get_logs/main.go b/usage-examples/go/admin-sdk/cmd/get_logs/main.go index ba2bb79..6c71f59 100644 --- a/usage-examples/go/admin-sdk/cmd/get_logs/main.go +++ b/usage-examples/go/admin-sdk/cmd/get_logs/main.go @@ -13,7 +13,6 @@ import ( ) const ( - // LogName is the name of the log file to download LogName = "mongodb" // valid values: "mongodb" or "mongos" ) diff --git a/usage-examples/go/admin-sdk/cmd/get_metrics/main.go b/usage-examples/go/admin-sdk/cmd/get_metrics/main.go index b95ade0..994fe19 100644 --- a/usage-examples/go/admin-sdk/cmd/get_metrics/main.go +++ b/usage-examples/go/admin-sdk/cmd/get_metrics/main.go @@ -12,11 +12,14 @@ import ( ) const ( - granularity = "P1D" - period = "P1D" - partitionName = "data" - processMetrics = "DB_DATA_SIZE_TOTAL,MAX_SYSTEM_MEMORY_AVAILABLE" - diskMetrics = "DISK_PARTITION_SPACE_FREE, DISK_PARTITION_SPACE_USED" + granularity = "P1D" + period = "P1D" + partitionName = "data" +) + +var ( + processMetrics = []string{"DB_DATA_SIZE_TOTAL", "MAX_SYSTEM_MEMORY_AVAILABLE"} + diskMetrics = []string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"} ) type GetProcessMetricParams struct { @@ -121,7 +124,7 @@ func main() { getProcessMetricParams := &GetProcessMetricParams{ GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, - M: &[]string{processMetrics}, + M: &processMetrics, Granularity: admin.PtrString(granularity), Period: admin.PtrString(period), } @@ -132,7 +135,7 @@ func main() { GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, PartitionName: partitionName, - M: &[]string{diskMetrics}, + M: &diskMetrics, Granularity: admin.PtrString(granularity), Period: admin.PtrString(period), } diff --git a/usage-examples/go/admin-sdk/configs/config.json b/usage-examples/go/admin-sdk/configs/config.json index f35e046..f26c851 100644 --- a/usage-examples/go/admin-sdk/configs/config.json +++ b/usage-examples/go/admin-sdk/configs/config.json @@ -1,9 +1,9 @@ { - "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "5bfda007553855125605a5cf", - "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", - "ATLAS_PORT": "27017", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017", +"ATLAS_BASE_URL": "https://cloud.mongodb.com", +"ATLAS_ORG_ID": "5bfda007553855125605a5cf", +"ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", +"ATLAS_CLUSTER_NAME": "Cluster0", +"ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", +"ATLAS_PORT": "27017", +"ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" } diff --git a/usage-examples/go/admin-sdk/go.mod b/usage-examples/go/admin-sdk/go.mod index 33406c3..475d942 100644 --- a/usage-examples/go/admin-sdk/go.mod +++ b/usage-examples/go/admin-sdk/go.mod @@ -4,10 +4,14 @@ go 1.24 require ( github.com/joho/godotenv v1.5.1 + github.com/stretchr/testify v1.10.0 go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/mongodb-forks/digest v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/usage-examples/go/admin-sdk/go.sum b/usage-examples/go/admin-sdk/go.sum index 21e7dad..f7ec5e3 100644 --- a/usage-examples/go/admin-sdk/go.sum +++ b/usage-examples/go/admin-sdk/go.sum @@ -14,5 +14,7 @@ go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1z go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/usage-examples/go/admin-sdk/internal/api_client.go b/usage-examples/go/admin-sdk/internal/api_client.go index d00d544..d7b26d1 100644 --- a/usage-examples/go/admin-sdk/internal/api_client.go +++ b/usage-examples/go/admin-sdk/internal/api_client.go @@ -7,17 +7,22 @@ import ( "net/http" ) -// HTTPClient is a thin wrapper around admin.APIClient for logs. +type AtlasClient interface { + GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) + GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) + GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) +} + type HTTPClient struct { sdk *admin.APIClient } -// NewAtlasClient initializes a new LogsService using admin.APIClient. +// NewAtlasClient creates a new Atlas API client using the provided SDK client func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { return &HTTPClient{sdk: sdk} } -// GetHostLogs fetches logs from MongoDB Atlas. +// GetHostLogs fetches MongoDB logs for the specified host in your project func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() if err != nil { @@ -26,6 +31,7 @@ func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsA return resp, nil } +// GetProcessMetrics fetches metrics for a specified host process in a project func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { resp, r, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() if err != nil { @@ -34,6 +40,7 @@ func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHos return resp, nil, nil } +// GetDiskMetrics fetches disk metrics for a specified disk partition in a project func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { resp, r, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() if err != nil { @@ -41,51 +48,3 @@ func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMe } return resp, nil, nil } - -// -//// OrganizationService provides organization-related methods -//type OrganizationService interface { -// ListOrganizations(ctx context.Context) (*admin.PaginatedOrganization, error) -//} -// -//// ProjectService provides project-related methods -//type ProjectService interface { -// ListProjects(ctx context.Context) (*admin.PaginatedAtlasGroup, error) -// -// GetProcesses(ctx context.Context, params *admin.ListAtlasProcessesApiParams) (*admin.PaginatedHostViewAtlas, error) -//} -// -//// ClusterService provides cluster-related methods -//type ClusterService interface { -// ListClusters(ctx context.Context) (*admin.PaginatedOrgGroup, error) -//} -// -//// LogsService provides log retrieval methods -//type LogsService interface { -// GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) -// -//} -// -//type MetricsService interface { -// GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *admin.APIResponse, error) -// -// GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.MeasurementDiskPartition, *admin.APIResponse, error) -// -// -//// AtlasClient combines all services into a single interface -//type AtlasClient interface { -// OrganizationService -// ProjectService -// ClusterService -// LogsService -// MetricsService -//} -// -//// HTTPAtlasClient is the concrete implementation of AtlasClient. -//type HTTPAtlasClient struct { -// sdk *admin.APIClient -//} -// -//func NewAtlasClient(sdk *admin.APIClient) *HTTPAtlasClient { -// return &HTTPAtlasClient{sdk: sdk} -//} diff --git a/usage-examples/go/admin-sdk/internal/auth/auth.go b/usage-examples/go/admin-sdk/internal/auth/auth.go index 76bdbcd..62ba88f 100644 --- a/usage-examples/go/admin-sdk/internal/auth/auth.go +++ b/usage-examples/go/admin-sdk/internal/auth/auth.go @@ -5,7 +5,10 @@ import ( "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" +) + +const ( + filePath = "./configs/config.json" ) // CreateAtlasClient initializes and returns an authenticated Atlas API client @@ -22,18 +25,12 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con if secrets.ServiceAccountID == "" || secrets.ServiceAccountSecret == "" { return nil, nil, nil, fmt.Errorf("missing Atlas client credentials") } - // Load configuration - config, err := internal.LoadConfig("configs/config-dev.json") + config, err := internal.LoadConfig(filePath) if err != nil { return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) } - // Check if ProcessID or Hostname:Port are set - if config.AtlasProcessID == "" || config.AtlasHostName == "" && config.AtlasPort == "" { - log.Fatal("Either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") - } - // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() sdk, err := admin.NewClient( diff --git a/usage-examples/go/admin-sdk/internal/config_loader.go b/usage-examples/go/admin-sdk/internal/config_loader.go index b68f91e..5cbcc4c 100644 --- a/usage-examples/go/admin-sdk/internal/config_loader.go +++ b/usage-examples/go/admin-sdk/internal/config_loader.go @@ -1,15 +1,11 @@ package internal import ( - "admin-sdk/utils" "encoding/json" "fmt" "os" - "strings" ) -var config Config - type Config struct { AtlasBaseURL string `json:"ATLAS_BASE_URL"` AtlasOrgID string `json:"ATLAS_ORG_ID"` @@ -18,7 +14,6 @@ type Config struct { AtlasHostName string `json:"ATLAS_HOST_NAME"` AtlasPort string `json:"ATLAS_PORT"` AtlasProcessID string `json:"ATLAS_PROCESS_ID"` - AppEnv string `json:"APP_ENV"` } // LoadConfig loads a JSON configs file into a Config struct @@ -26,7 +21,7 @@ type Config struct { func LoadConfig(filePath string) (*Config, error) { file, err := os.Open(filePath) if err != nil { - return nil, fmt.Errorf("error opening configs file: %w", err) + return nil, fmt.Errorf("error opening config file: %w", err) } defer func(file *os.File) { err := file.Close() @@ -35,43 +30,41 @@ func LoadConfig(filePath string) (*Config, error) { } }(file) + var config Config decoder := json.NewDecoder(file) if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding configs file: %w", err) + return nil, fmt.Errorf("error decoding config file: %w", err) } return &config, nil } // GetConfigFilePath returns the correct config file based on the environment -func (c *Config) GetConfigFilePath(string) string { - return fmt.Sprintf("configs/config-%s.json") -} +//func (c *Config) GetConfigFilePath(appEnv string) string { +// return fmt.Sprintf("configs/config-%s.json", c.AppEnv) +//} // SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if utils.IsEmptyString(c.AtlasBaseURL) { - c.AtlasBaseURL = "https://cloud.mongodb.com" - } - if utils.IsEmptyString(c.AtlasPort) { - c.AtlasPort = "27017" - } - if utils.IsEmptyString(c.AtlasProcessID) && !utils.IsEmptyString(c.AtlasHostName) { - c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort - } - if utils.IsEmptyString(c.AtlasHostName) { - c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] - } - if utils.IsEmptyString(c.AppEnv) { - c.AppEnv = "dev" // Default to development - } -} - -func (c *Config) CheckRequiredFields() error { - if utils.IsEmptyString(c.AtlasOrgID) || utils.IsEmptyString(c.AtlasProjectID) { - return fmt.Errorf("missing required Atlas fields in config file") - } - if utils.IsEmptyString(c.AtlasProcessID) || utils.IsEmptyString(c.AtlasHostName) && utils.IsEmptyString(c.AtlasPort) { - return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") - } - return nil -} +//func (c *Config) SetDefaults() { +// if utils.IsEmptyString(c.AtlasBaseURL) { +// c.AtlasBaseURL = "https://cloud.mongodb.com" +// } +// if utils.IsEmptyString(c.AtlasPort) { +// c.AtlasPort = "27017" +// } +// if utils.IsEmptyString(c.AtlasProcessID) && !utils.IsEmptyString(c.AtlasHostName) { +// c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort +// } +// if utils.IsEmptyString(c.AtlasHostName) { +// c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] +// } +//} +// +//func (c *Config) CheckRequiredFields() error { +// if utils.IsEmptyString(c.AtlasOrgID) || utils.IsEmptyString(c.AtlasProjectID) { +// return fmt.Errorf("missing required Atlas fields in config file") +// } +// if utils.IsEmptyString(c.AtlasProcessID) || utils.IsEmptyString(c.AtlasHostName) && utils.IsEmptyString(c.AtlasPort) { +// return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") +// } +// return nil +//} diff --git a/usage-examples/go/admin-sdk/internal/mocks.go b/usage-examples/go/admin-sdk/internal/mocks.go index 0fd12e0..9960a42 100644 --- a/usage-examples/go/admin-sdk/internal/mocks.go +++ b/usage-examples/go/admin-sdk/internal/mocks.go @@ -4,27 +4,42 @@ import ( "context" "go.mongodb.org/atlas-sdk/v20250219001/admin" "io" + "net/http" "strings" ) -// Abstract the Atlas API client into an interface to allow for mocking. +// NOTE: We're using mocked tests because Monitoring and Logging functionality requires a dedicated cluster (M10+) -// LogsService is a minimal interface for fetching logs. -type LogsService interface { - GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) +// MockAtlasClient is a fake implementation of AtlasClient for testing. +type MockAtlasClient struct { + FakeHostLogsResponse string + FakeHostLogsError error + FakeProcessMetricsResponse *admin.ApiMeasurementsGeneralViewAtlas + FakeProcessMetricsError error + FakeDiskMetricsResponse *admin.ApiMeasurementsGeneralViewAtlas + FakeDiskMetricsError error } -// MockLogsClient is a fake implementation of LogsService for testing. -type MockLogsClient struct { - FakeResponse string - FakeError error +// GetHostLogs returns a fake log response or an error. +func (m *MockAtlasClient) GetHostLogs(context.Context, *admin.GetHostLogsApiParams) (io.ReadCloser, error) { + if m.FakeHostLogsError != nil { + return nil, m.FakeHostLogsError + } + return io.NopCloser(strings.NewReader(m.FakeHostLogsResponse)), nil } -// GetHostLogs returns a fake log response or an error. -func (m *MockLogsClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { - if m.FakeError != nil { - return nil, m.FakeError +// GetProcessMetrics returns fake process metrics or an error. +func (m *MockAtlasClient) GetProcessMetrics(context.Context, *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { + if m.FakeProcessMetricsError != nil { + return nil, nil, m.FakeProcessMetricsError + } + return m.FakeProcessMetricsResponse, nil, nil +} + +// GetDiskMetrics returns fake disk metrics or an error. +func (m *MockAtlasClient) GetDiskMetrics(context.Context, *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { + if m.FakeDiskMetricsError != nil { + return nil, nil, m.FakeDiskMetricsError } - // Simulate a log file as a string - return io.NopCloser(strings.NewReader(m.FakeResponse)), nil + return m.FakeDiskMetricsResponse, nil, nil } diff --git a/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go b/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go deleted file mode 100644 index aa107c0..0000000 --- a/usage-examples/go/admin-sdk/tests/get_logs_metrics_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package tests - -//func TestExample(t *testing.T) { -// notMain.ExampleMain(t) -//} - -// interface apiclient > stubbed response diff --git a/usage-examples/go/admin-sdk/tests/logs_test.go b/usage-examples/go/admin-sdk/tests/logs_test.go deleted file mode 100644 index 80fb4dc..0000000 --- a/usage-examples/go/admin-sdk/tests/logs_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package tests - -//import ( -// "context" -// "errors" -// "myapp/internal" -// "myapp/scripts" -// "testing" -//) -// -//// TestGetHostLogsSuccess ensures logs are fetched successfully. -//func TestGetHostLogsSuccess(t *testing.T) { -// ctx := context.Background() -// -// // Mock client returns fake log data -// mockClient := &internal.MockLogsClient{ -// FakeResponse: "Test log entry\n", -// } -// -// err := scripts.GetHostLogs(ctx, mockClient, "123456", "test-host", "mongodb.log") -// if err != nil { -// t.Fatalf("Unexpected error: %v", err) -// } -//} -// -//// TestGetHostLogsFailure simulates an API failure. -//func TestGetHostLogsFailure(t *testing.T) { -// ctx := context.Background() -// -// // Mock client returns an error -// mockClient := &internal.MockLogsClient{ -// FakeError: errors.New("mock API failure"), -// } -// -// err := scripts.GetHostLogs(ctx, mockClient, "123456", "test-host", "mongodb.log") -// if err == nil { -// t.Fatalf("Expected error but got none") -// } -//} diff --git a/usage-examples/go/admin-sdk/tests/mock_test.go b/usage-examples/go/admin-sdk/tests/mock_test.go new file mode 100644 index 0000000..720ed8c --- /dev/null +++ b/usage-examples/go/admin-sdk/tests/mock_test.go @@ -0,0 +1,170 @@ +package test + +import ( + "admin-sdk/internal" + "bytes" + "compress/gzip" + "context" + "github.com/stretchr/testify/assert" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "testing" +) + +var ( + testGroupID = "test-group-id" + testHostName = "test-host-name" + testProcessID = "test-process-id" + testLogName = "mongodb" + testTimeStamp = "2023-01-01T00:00:00Z" + testPartition = "data" + testLogResponse = "log content" +) + +func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { + // Set up a Gzip.Writer + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + _, err := gz.Write([]byte(testLogResponse)) + assert.NoError(t, err) + err = gz.Close() + assert.NoError(t, err) + + // Initialize mock client with compressed log data stored in buffer + mockClient := &internal.MockAtlasClient{ + FakeHostLogsResponse: buf.String(), + } + + // Call GetHostLogs to download the log.gz file + resp, err := mockClient.GetHostLogs(context.Background(), &admin.GetHostLogsApiParams{}) + assert.NoError(t, err) + assert.NotNil(t, resp) + + // Read the downloaded log.gz file + gzReader, err := gzip.NewReader(resp) + assert.NoError(t, err) + defer func(gzReader *gzip.Reader) { + err := gzReader.Close() + if err != nil { + t.Errorf("failed to close gzip reader: %v", err) + } + }(gzReader) + + // Verify compressed data with the original log content + var result bytes.Buffer + _, err = io.Copy(&result, gzReader) + assert.NoError(t, err) + assert.Equal(t, testLogResponse, result.String()) +} + +func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { + mockClient := &internal.MockAtlasClient{ + FakeHostLogsResponse: testLogResponse, + FakeHostLogsError: nil, + } + + ctx := context.Background() + params := &admin.GetHostLogsApiParams{ + GroupId: testGroupID, + HostName: testHostName, + LogName: testLogName, + } + + resp, err := mockClient.GetHostLogs(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + ActualLogResponse, err := io.ReadAll(resp) + if err != nil { + t.Fatalf("failed to read log content: %v", err) + } + + if string(ActualLogResponse) != testLogResponse { + t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) + } +} + +func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { + expectedMetricName := "DB_DATA_SIZE_TOTAL" + parsedTime, _ := admin.StringToTime(testTimeStamp) + parsedTimeValue := float32(100) + + mockClient := &internal.MockAtlasClient{ + FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{ + { + Name: admin.PtrString(expectedMetricName), + DataPoints: &[]admin.MetricDataPointAtlas{ + {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, + }, + }, + }, + }, + FakeProcessMetricsError: nil, + } + + ctx := context.Background() + params := &admin.GetHostMeasurementsApiParams{ + GroupId: testGroupID, + ProcessId: testProcessID, + } + + resp, _, err := mockClient.GetProcessMetrics(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if resp.HasMeasurements() == false { + t.Errorf("expected measurements, got none") + } + + measurements := resp.GetMeasurements() + actualMetricName := measurements[0].GetName() + if actualMetricName != expectedMetricName { + t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) + } +} + +func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { + + expectedMetricName := "DISK_PARTITION_SPACE_FREE" + parsedTime, _ := admin.StringToTime(testTimeStamp) + parsedTimeValue := float32(500) + + mockClient := &internal.MockAtlasClient{ + FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{ + { + Name: admin.PtrString(expectedMetricName), + DataPoints: &[]admin.MetricDataPointAtlas{ + {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, + }, + }, + }, + }, + FakeDiskMetricsError: nil, + } + + ctx := context.Background() + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: testGroupID, + ProcessId: testProcessID, + PartitionName: testPartition, + } + + resp, _, err := mockClient.GetDiskMetrics(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if resp.HasMeasurements() == false { + t.Errorf("expected measurements, got none") + } + + measurements := resp.GetMeasurements() + actualMetricName := measurements[0].GetName() + if actualMetricName != expectedMetricName { + t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) + } +} From a995b32af8af8e1f47bdbf4d1c42e1093162a104 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Wed, 19 Mar 2025 15:36:57 -0400 Subject: [PATCH 09/22] Update /generated-usage-examples subdirectories to match new structure --- usage-examples/go/admin-sdk/README.md | 22 -------- usage-examples/go/admin-sdk/bluehawk.sh | 9 --- .../go/admin-sdk/configs/config-dev.json | 9 --- .../go/admin-sdk/configs/config-prod.json | 9 --- .../go/admin-sdk/configs/config.json | 9 --- .../go/admin-sdk/internal/secrets_loader.go | 34 ------------ usage-examples/go/admin-sdk/scripts/types.go | 55 ------------------- usage-examples/go/atlas-sdk-go/README.md | 25 +++++++++ usage-examples/go/atlas-sdk-go/bluehawk.sh | 14 +++++ .../cmd/get_logs/main.go | 21 ++++--- .../cmd/get_metrics/main.go | 37 +++++++------ .../go/{admin-sdk => atlas-sdk-go}/go.mod | 0 .../go/{admin-sdk => atlas-sdk-go}/go.sum | 0 .../internal/api_client.go | 3 + .../internal/auth/auth.go | 3 + .../internal/config_loader.go | 5 +- .../internal/mocks.go | 0 .../atlas-sdk-go/internal/secrets_loader.go | 36 ++++++++++++ usage-examples/go/atlas-sdk-go/run_cmd.sh | 19 +++++++ .../tests/mock_test.go | 0 .../utils/utility.go | 3 + 21 files changed, 141 insertions(+), 172 deletions(-) delete mode 100644 usage-examples/go/admin-sdk/README.md delete mode 100644 usage-examples/go/admin-sdk/bluehawk.sh delete mode 100644 usage-examples/go/admin-sdk/configs/config-dev.json delete mode 100644 usage-examples/go/admin-sdk/configs/config-prod.json delete mode 100644 usage-examples/go/admin-sdk/configs/config.json delete mode 100644 usage-examples/go/admin-sdk/internal/secrets_loader.go delete mode 100644 usage-examples/go/admin-sdk/scripts/types.go create mode 100644 usage-examples/go/atlas-sdk-go/README.md create mode 100755 usage-examples/go/atlas-sdk-go/bluehawk.sh rename usage-examples/go/{admin-sdk => atlas-sdk-go}/cmd/get_logs/main.go (73%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/cmd/get_metrics/main.go (80%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/go.mod (100%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/go.sum (100%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/internal/api_client.go (94%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/internal/auth/auth.go (93%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/internal/config_loader.go (91%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/internal/mocks.go (100%) create mode 100644 usage-examples/go/atlas-sdk-go/internal/secrets_loader.go create mode 100755 usage-examples/go/atlas-sdk-go/run_cmd.sh rename usage-examples/go/{admin-sdk => atlas-sdk-go}/tests/mock_test.go (100%) rename usage-examples/go/{admin-sdk => atlas-sdk-go}/utils/utility.go (94%) diff --git a/usage-examples/go/admin-sdk/README.md b/usage-examples/go/admin-sdk/README.md deleted file mode 100644 index 643d4fb..0000000 --- a/usage-examples/go/admin-sdk/README.md +++ /dev/null @@ -1,22 +0,0 @@ -```text -my-go-project/ -│── scripts/ # ✅ Self-contained, runnable scripts -│ ├── get_invoices.go # Script to fetch invoices -│ ├── fetch_logs.go # Script to retrieve logs -│ ├── delete_old_data.go # Script to delete data -│── config/ # ✅ Configuration directory -│ ├── config.json # General app settings (non-sensitive) -│ ├── logging.json # Logging settings -│ ├── database.json # Database settings (no credentials) -│ ├── features.json # Feature flags and toggles -│── secrets/ # ✅ Secure secrets directory (excluded from Git) -│ ├── secrets.json # 🔐 API keys, database credentials -│── internal/ # ✅ Shared internal logic -│ ├── config_loader.go # Loads JSON configs -│ ├── secrets_loader.go # Loads secrets securely -│── .gitignore # Exclude secrets.json -│── go.mod # Go module file -│── go.sum # Dependency checksums -│── README.md # Documentation - -``` diff --git a/usage-examples/go/admin-sdk/bluehawk.sh b/usage-examples/go/admin-sdk/bluehawk.sh deleted file mode 100644 index d6bd856..0000000 --- a/usage-examples/go/admin-sdk/bluehawk.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -PROJECT=$(git rev-parse --show-toplevel) -GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/admin-sdk/config:$PROJECT/usage-examples/go/admin-sdk/scripts:$PROJECT/usage-examples/go/admin-sdk/internal:$PROJECT/usage-examples/go/admin-sdk/types -GENERATED_EXAMPLES=$PROJECT/generated-examples/go/admin-sdk - -# Bluehawk Admin Go SDK examples -echo "Bluehawking Admin Go SDK examples" -npx bluehawk snip $GO_SDK_EXAMPLES -o $GENERATED_EXAMPLES diff --git a/usage-examples/go/admin-sdk/configs/config-dev.json b/usage-examples/go/admin-sdk/configs/config-dev.json deleted file mode 100644 index 46c9a4d..0000000 --- a/usage-examples/go/admin-sdk/configs/config-dev.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "5bfda007553855125605a5cf", - "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", - "ATLAS_PORT": "27017", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" -} diff --git a/usage-examples/go/admin-sdk/configs/config-prod.json b/usage-examples/go/admin-sdk/configs/config-prod.json deleted file mode 100644 index 46c9a4d..0000000 --- a/usage-examples/go/admin-sdk/configs/config-prod.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "5bfda007553855125605a5cf", - "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", - "ATLAS_PORT": "27017", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" -} diff --git a/usage-examples/go/admin-sdk/configs/config.json b/usage-examples/go/admin-sdk/configs/config.json deleted file mode 100644 index f26c851..0000000 --- a/usage-examples/go/admin-sdk/configs/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ -"ATLAS_BASE_URL": "https://cloud.mongodb.com", -"ATLAS_ORG_ID": "5bfda007553855125605a5cf", -"ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", -"ATLAS_CLUSTER_NAME": "Cluster0", -"ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", -"ATLAS_PORT": "27017", -"ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" -} diff --git a/usage-examples/go/admin-sdk/internal/secrets_loader.go b/usage-examples/go/admin-sdk/internal/secrets_loader.go deleted file mode 100644 index d2c53dc..0000000 --- a/usage-examples/go/admin-sdk/internal/secrets_loader.go +++ /dev/null @@ -1,34 +0,0 @@ -package internal - -import ( - "github.com/joho/godotenv" - "log" - "os" -) - -// Secrets structure -type Secrets struct { - MongoDBUser string `json:"MONGODB_USER_NAME"` - MongoDBPassword string `json:"MONGODB_PASSWORD"` - AtlasAPIKey string `json:"MONGODB_ATLAS_PUBLIC_API_KEY"` - AtlasAPISecret string `json:"MONGODB_ATLAS_PRIVATE_KEY"` - ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` - ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` -} - -// LoadSecrets loads environment variables from a .env file into a Secrets struct -// and returns a pointer -func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load(".env"); err != nil { - log.Println("No .env file found") - } - secrets := &Secrets{ - MongoDBUser: os.Getenv("MONGODB_USER_NAME"), - MongoDBPassword: os.Getenv("MONGODB_PASSWORD"), - AtlasAPIKey: os.Getenv("MONGODB_ATLAS_PUBLIC_KEY"), - AtlasAPISecret: os.Getenv("MONGODB_ATLAS_PRIVATE_KEY"), - ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), - ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), - } - return secrets, nil -} diff --git a/usage-examples/go/admin-sdk/scripts/types.go b/usage-examples/go/admin-sdk/scripts/types.go deleted file mode 100644 index 1f348e6..0000000 --- a/usage-examples/go/admin-sdk/scripts/types.go +++ /dev/null @@ -1,55 +0,0 @@ -// :snippet-start: script-structs -package main - -import "time" - -type ListAtlasProcessesParams struct { - GroupID string `json:"groupId"` - IncludeCount *bool `json:"includeCount,omitempty"` - ItemsPerPage *int `json:"itemsPerPage,omitempty"` - PageNum *int `json:"pageNum,omitempty"` -} - -type Z_GetHostLogsParams struct { - GroupID string `json:"groupId"` - HostName string `json:"hostName"` - LogName string `json:"logName"` - EndDate *int64 `json:"endDate,omitempty"` - StartDate *int64 `json:"startDate,omitempty"` -} - -type ListProjectsParams struct { - GroupID string `json:"groupId"` - ItemsPerPage *int `json:"itemsPerPage,omitempty"` - IncludeCount *bool `json:"includeCount,omitempty"` - PageNum *int `json:"pageNum,omitempty"` -} - -type Z_HostMetricParams struct { - GroupID string `json:"groupId"` - ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics"` - Period *string `json:"period"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} -type Z_ClusterMetricParams struct { - GroupID string `json:"groupId"` - ProcessID string `json:"processId"` - PartitionName string `json:"partitionName"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"period,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -type Measurement struct { - Name string `json:"name"` - Data []MetricDataPointAtlas `json:"data"` -} - -type MetricDataPointAtlas struct { - Timestamp string `json:"timestamp"` - Value float64 `json:"value"` -} diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md new file mode 100644 index 0000000..a9a3106 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -0,0 +1,25 @@ +```text +atlas-sdk-go/ +│── cmd/ # ✅ Self-contained, runnable scripts +│ ├── get_logs/ # Script to fetch invoices +│ ├── main.go # Script to retrieve logs +│ ├── get_metrics/ # Script to fetch invoices +│ ├── main.go # Script to delete data +│── config/ # ✅ Configuration directory +│ ├── config.json # General app settings (non-sensitive) +│── internal/ # ✅ Shared internal logic +│ ├── config_loader.go # Loads JSON configs +│ ├── secrets_loader.go # Loads secrets securely +│── .gitignore # Exclude secrets.json +│── go.mod # Go module file +│── go.sum # Dependency checksums +│── README.md # Documentation + + +```shell +./bluehawk.sh +``` + +```shell +./run_cmd.sh get_logs +``` diff --git a/usage-examples/go/atlas-sdk-go/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk.sh new file mode 100755 index 0000000..f943ba9 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/bluehawk.sh @@ -0,0 +1,14 @@ +#! /bin/bash + +PROJECT=$(git rev-parse --show-toplevel) +# This project requires Bluehawking multiple directories so the generated code can be copied to the user-facing `atlas-architecture-center-go-sdk` repo +GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/admin-sdk/config:$PROJECT/usage-examples/go/admin-sdk/scripts:$PROJECT/usage-examples/go/admin-sdk/internal:$PROJECT/usage-examples/go/admin-sdk/types +GENERATED_EXAMPLES=$PROJECT/generated-examples/go/admin-sdk + +# Bluehawk Admin Go SDK examples +echo "Running Bluehawk snip on $GO_SDK_EXAMPLES..." +echo "Extracting snippets to the $GENERATED_EXAMPLES directory" +npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" + +# Clean up any .gz log files +find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/admin-sdk/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go similarity index 73% rename from usage-examples/go/admin-sdk/cmd/get_logs/main.go rename to usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 6c71f59..1ac0e9b 100644 --- a/usage-examples/go/admin-sdk/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -1,3 +1,4 @@ +// :snippet-start: get-logs-full-script package main import ( @@ -13,20 +14,20 @@ import ( ) const ( - LogName = "mongodb" // valid values: "mongodb" or "mongos" + LogName = "mongodb" ) type GetHostLogsParams struct { - GroupID string `json:"groupId"` // GroupID == ProjectID + GroupID string `json:"groupId"` // Note: GroupID == ProjectID HostName string `json:"hostName"` - LogName string `json:"logName"` + LogName string `json:"logName"` // valid values: "mongodb" or "mongos" EndDate *int64 `json:"endDate,omitempty"` StartDate *int64 `json:"startDate,omitempty"` } // Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { - fmt.Printf("Fetching logs for project %s, host %s, log %s...\n", hostParams.GroupID, hostParams.HostName, hostParams.LogName) + fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) // Create request params params := &admin.GetHostLogsApiParams{ @@ -63,7 +64,7 @@ func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *Ge } }(logFile) - // Write logs to file + // Write compressed logs to file if _, err = io.Copy(logFile, resp); err != nil { return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) } @@ -71,17 +72,23 @@ func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *Ge return nil } +// :snippet-start: get-logs-main func main() { ctx := context.Background() + // Create an Atlas client authenticated using OAuth2 with service account credentials client, _, config, err := auth.CreateAtlasClient() utils.HandleError(err, "Failed to create Atlas client") params := &GetHostLogsParams{ GroupID: config.AtlasProjectID, - HostName: config.AtlasHostName, - LogName: LogName, + HostName: config.AtlasHostName, // The host to get logs for + LogName: LogName, // The type of log to get ("mongodb" or "mongos") } + // Downloads the specified host's MongoDB logs as a .gz file utils.HandleError(getHostLogs(ctx, *client, params), "Error fetching host logs") } + +// :snippet-end: [get-logs-main] +// :snippet-end: [get-logs-full-script] diff --git a/usage-examples/go/admin-sdk/cmd/get_metrics/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go similarity index 80% rename from usage-examples/go/admin-sdk/cmd/get_metrics/main.go rename to usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go index 994fe19..5471cb0 100644 --- a/usage-examples/go/admin-sdk/cmd/get_metrics/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go @@ -1,3 +1,4 @@ +// :snippet-start: get-metrics-full-script package main import ( @@ -11,6 +12,7 @@ import ( "time" ) +// Define parameters for the metrics to fetch const ( granularity = "P1D" period = "P1D" @@ -23,20 +25,20 @@ var ( ) type GetProcessMetricParams struct { - GroupID string `json:"groupId"` // GroupID == ProjectID + GroupID string `json:"groupId"` // Note: GroupID == ProjectID ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics"` - Period *string `json:"period"` + Granularity string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"period,omitempty"` Start *time.Time `json:"start,omitempty"` End *time.Time `json:"end,omitempty"` } type GetDiskMetricParams struct { - GroupID string `json:"groupId"` + GroupID string `json:"groupId"` // Note: GroupID == ProjectID ProcessID string `json:"processId"` PartitionName string `json:"partitionName"` - Granularity *string `json:"granularity"` + Granularity string `json:"granularity"` M *[]string `json:"metrics,omitempty"` Period *string `json:"period,omitempty"` Start *time.Time `json:"start,omitempty"` @@ -50,7 +52,7 @@ func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostPara params := &admin.GetHostMeasurementsApiParams{ GroupId: hostParams.GroupID, ProcessId: hostParams.ProcessID, - Granularity: hostParams.Granularity, + Granularity: &hostParams.Granularity, M: hostParams.M, Period: hostParams.Period, Start: hostParams.Start, @@ -85,7 +87,7 @@ func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams GroupId: diskParams.GroupID, ProcessId: diskParams.ProcessID, PartitionName: diskParams.PartitionName, - Granularity: diskParams.Granularity, + Granularity: &diskParams.Granularity, M: diskParams.M, Period: diskParams.Period, Start: diskParams.Start, @@ -99,7 +101,6 @@ func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams } return fmt.Errorf("failed to get measurements: %w", err) } - if resp == nil || resp.HasMeasurements() == false { return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) } @@ -110,10 +111,10 @@ func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams } fmt.Println(string(jsonData)) - return nil } +// :snippet-start: get-metrics-main func main() { ctx := context.Background() client, _, config, err := auth.CreateAtlasClient() @@ -125,20 +126,24 @@ func main() { GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, M: &processMetrics, - Granularity: admin.PtrString(granularity), + Granularity: granularity, Period: admin.PtrString(period), } - err = getProcessMetrics(ctx, *client, getProcessMetricParams) - utils.HandleError(err, "Error fetching host process metrics") + utils.HandleError(getProcessMetrics(ctx, *client, getProcessMetricParams), + "Error fetching host process metrics") getDiskMetricParams := &GetDiskMetricParams{ GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, PartitionName: partitionName, M: &diskMetrics, - Granularity: admin.PtrString(granularity), + Granularity: granularity, Period: admin.PtrString(period), } - err = getDiskMetrics(ctx, *client, getDiskMetricParams) - utils.HandleError(err, "Error fetching partition disk metrics") + + utils.HandleError(getDiskMetrics(ctx, *client, getDiskMetricParams), + "Error fetching partition disk metrics") } + +// :snippet-end: [get-metrics-main] +// :snippet-end: [get-metrics-full-script] diff --git a/usage-examples/go/admin-sdk/go.mod b/usage-examples/go/atlas-sdk-go/go.mod similarity index 100% rename from usage-examples/go/admin-sdk/go.mod rename to usage-examples/go/atlas-sdk-go/go.mod diff --git a/usage-examples/go/admin-sdk/go.sum b/usage-examples/go/atlas-sdk-go/go.sum similarity index 100% rename from usage-examples/go/admin-sdk/go.sum rename to usage-examples/go/atlas-sdk-go/go.sum diff --git a/usage-examples/go/admin-sdk/internal/api_client.go b/usage-examples/go/atlas-sdk-go/internal/api_client.go similarity index 94% rename from usage-examples/go/admin-sdk/internal/api_client.go rename to usage-examples/go/atlas-sdk-go/internal/api_client.go index d7b26d1..48c88dd 100644 --- a/usage-examples/go/admin-sdk/internal/api_client.go +++ b/usage-examples/go/atlas-sdk-go/internal/api_client.go @@ -1,3 +1,4 @@ +// :snippet-start: api-client-function-full-example package internal import ( @@ -48,3 +49,5 @@ func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMe } return resp, nil, nil } + +// :snippet-end: [api-client-function-full-example] diff --git a/usage-examples/go/admin-sdk/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go similarity index 93% rename from usage-examples/go/admin-sdk/internal/auth/auth.go rename to usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 62ba88f..9246046 100644 --- a/usage-examples/go/admin-sdk/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -1,3 +1,4 @@ +// :snippet-start: auth-function-full-example package auth import ( @@ -45,3 +46,5 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con return client, secrets, config, nil } + +// :snippet-end: [auth-function-full-example] diff --git a/usage-examples/go/admin-sdk/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go similarity index 91% rename from usage-examples/go/admin-sdk/internal/config_loader.go rename to usage-examples/go/atlas-sdk-go/internal/config_loader.go index 5cbcc4c..7c94e19 100644 --- a/usage-examples/go/admin-sdk/internal/config_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/config_loader.go @@ -1,3 +1,4 @@ +// :snippet-start: config-loader-function-full-example package internal import ( @@ -16,8 +17,7 @@ type Config struct { AtlasProcessID string `json:"ATLAS_PROCESS_ID"` } -// LoadConfig loads a JSON configs file into a Config struct -// takes a file path as an argument and returns a pointer to a Config struct and an error +// LoadConfig loads a JSON config file to make it available to the application func LoadConfig(filePath string) (*Config, error) { file, err := os.Open(filePath) if err != nil { @@ -38,6 +38,7 @@ func LoadConfig(filePath string) (*Config, error) { return &config, nil } +// :snippet-end: [config-loader-function-full-example] // GetConfigFilePath returns the correct config file based on the environment //func (c *Config) GetConfigFilePath(appEnv string) string { // return fmt.Sprintf("configs/config-%s.json", c.AppEnv) diff --git a/usage-examples/go/admin-sdk/internal/mocks.go b/usage-examples/go/atlas-sdk-go/internal/mocks.go similarity index 100% rename from usage-examples/go/admin-sdk/internal/mocks.go rename to usage-examples/go/atlas-sdk-go/internal/mocks.go diff --git a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go new file mode 100644 index 0000000..0603cc6 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go @@ -0,0 +1,36 @@ +// :snippet-start: secrets-loader-function-full-example + +package internal + +import ( + "github.com/joho/godotenv" + "log" + "os" +) + +type Secrets struct { + MongoDBUser string `json:"MONGODB_USER_NAME"` // :remove: + MongoDBPassword string `json:"MONGODB_PASSWORD"` // :remove: + AtlasAPIKey string `json:"MONGODB_ATLAS_PUBLIC_API_KEY"` // :remove: + AtlasAPISecret string `json:"MONGODB_ATLAS_PRIVATE_KEY"` // :remove: + ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` + ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` +} + +// LoadSecrets loads environment variables from a .env file to use in the application +func LoadSecrets() (*Secrets, error) { + if err := godotenv.Load(".env"); err != nil { + log.Println("No .env file found") + } + secrets := &Secrets{ + MongoDBUser: os.Getenv("MONGODB_USER_NAME"), // :remove: + MongoDBPassword: os.Getenv("MONGODB_PASSWORD"), // :remove: + AtlasAPIKey: os.Getenv("MONGODB_ATLAS_PUBLIC_KEY"), // :remove: + AtlasAPISecret: os.Getenv("MONGODB_ATLAS_PRIVATE_KEY"), // :remove: + ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), + ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), + } + return secrets, nil +} + +// :snippet-end: [secrets-loader-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/run_cmd.sh b/usage-examples/go/atlas-sdk-go/run_cmd.sh new file mode 100755 index 0000000..93d2175 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/run_cmd.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Check if an action is provided +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +ACTION=$1 +MAIN_FILE="cmd/$ACTION/main.go" + +# Check if the main.go file exists for the given action +if [ ! -f "$MAIN_FILE" ]; then + echo "Error: $MAIN_FILE does not exist." + exit 1 +fi + +# Run the main.go file +go run "$MAIN_FILE" diff --git a/usage-examples/go/admin-sdk/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go similarity index 100% rename from usage-examples/go/admin-sdk/tests/mock_test.go rename to usage-examples/go/atlas-sdk-go/tests/mock_test.go diff --git a/usage-examples/go/admin-sdk/utils/utility.go b/usage-examples/go/atlas-sdk-go/utils/utility.go similarity index 94% rename from usage-examples/go/admin-sdk/utils/utility.go rename to usage-examples/go/atlas-sdk-go/utils/utility.go index fa8fe5f..e3bdee5 100644 --- a/usage-examples/go/admin-sdk/utils/utility.go +++ b/usage-examples/go/atlas-sdk-go/utils/utility.go @@ -1,3 +1,4 @@ +// :snippet-start: utility-functions-full-example package utils import ( @@ -75,3 +76,5 @@ func Retry(attempts int, sleep time.Duration, fn func() error) error { } return fmt.Errorf("reached maximum retry attempts") } + +// :snippet-end: [utility-functions-full-example] From df0261f7bf49fdadd33bbbfe9e17b9ccac856a99 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 20 Mar 2025 01:26:00 -0400 Subject: [PATCH 10/22] Bluehawk examples to sdk/snippets and atlas-sdk-go/ --- .../go/atlas-sdk-go/README.md | 25 ++++ .../main.snippet.get-logs-full-script.go | 95 +++++++++++++ .../main.snippet.get-metrics-full-script.go | 112 +++++++++++++++ .../go/atlas-sdk-go/configs/config.json | 9 ++ ...nippet.api-client-function-full-example.go | 50 +++++++ ...auth.snippet.auth-function-full-example.go | 49 +++++++ ...auth.snippet.auth-function-full-example.go | 49 +++++++ ...pet.config-loader-function-full-example.go | 67 +++++++++ ...et.secrets-loader-function-full-example.go | 35 +++++ ...ann-basic-with-scenario.snippet.example.go | 0 .../{ => driver}/ann-basic.snippet.example.go | 0 ...nn-filter-with-scenario.snippet.example.go | 0 .../ann-filter.snippet.example.go | 0 .../create-index-basic.snippet.example.go | 0 .../create-index-filter.snippet.example.go | 0 ...-filter-using-scenarios.snippet.example.go | 0 .../drop-index.snippet.example.go | 0 .../edit-index.snippet.example.go | 0 .../go/{ => driver}/enn.snippet.example.go | 0 .../view-index.snippet.example.go | 0 .../sdk/main.snippet.get-logs-full-script.go | 95 +++++++++++++ .../go/sdk/main.snippet.get-logs-main.go | 21 +++ .../main.snippet.get-metrics-full-script.go | 132 ++++++++++++++++++ .../sdk/main.snippet.get-metrics-main-dev.go | 30 ++++ .../sdk/main.snippet.get-metrics-main-prod.go | 30 ++++ .../AnnQueryBasic.snippet.example.java | 0 .../AnnQueryFilter.snippet.example.java | 0 .../CreateIndexBasic.snippet.example.java | 0 .../CreateIndexFilter.snippet.example.java | 0 .../{ => sync}/DropIndex.snippet.example.java | 0 .../{ => sync}/ViewIndex.snippet.example.java | 0 usage-examples/go/atlas-sdk-go/README.md | 37 ++--- usage-examples/go/atlas-sdk-go/bluehawk.sh | 11 +- .../go/atlas-sdk-go/bluehawkProject.sh | 45 ++++++ .../go/atlas-sdk-go/cmd/get_logs/main.go | 26 +++- .../go/atlas-sdk-go/cmd/get_metrics/main.go | 88 +++++++----- usage-examples/go/atlas-sdk-go/go.mod | 2 +- .../go/atlas-sdk-go/internal/api_client.go | 21 ++- .../go/atlas-sdk-go/internal/auth/auth.go | 17 +-- .../go/atlas-sdk-go/internal/config_loader.go | 54 +++---- .../go/atlas-sdk-go/internal/mocks.go | 1 - .../atlas-sdk-go/internal/secrets_loader.go | 11 +- .../go/atlas-sdk-go/tests/cleanup.go | 33 +++++ .../go/atlas-sdk-go/tests/mock_test.go | 2 +- .../go/atlas-sdk-go/utils/utility.go | 80 ----------- 45 files changed, 1032 insertions(+), 195 deletions(-) create mode 100644 generated-usage-examples/go/atlas-sdk-go/README.md create mode 100644 generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/configs/config.json create mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go rename generated-usage-examples/go/{ => driver}/ann-basic-with-scenario.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/ann-basic.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/ann-filter-with-scenario.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/ann-filter.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/create-index-basic.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/create-index-filter.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/create-index-without-filter-using-scenarios.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/drop-index.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/edit-index.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/enn.snippet.example.go (100%) rename generated-usage-examples/go/{ => driver}/view-index.snippet.example.go (100%) create mode 100644 generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go create mode 100644 generated-usage-examples/go/sdk/main.snippet.get-logs-main.go create mode 100644 generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go create mode 100644 generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go create mode 100644 generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go rename generated-usage-examples/java/{ => sync}/AnnQueryBasic.snippet.example.java (100%) rename generated-usage-examples/java/{ => sync}/AnnQueryFilter.snippet.example.java (100%) rename generated-usage-examples/java/{ => sync}/CreateIndexBasic.snippet.example.java (100%) rename generated-usage-examples/java/{ => sync}/CreateIndexFilter.snippet.example.java (100%) rename generated-usage-examples/java/{ => sync}/DropIndex.snippet.example.java (100%) rename generated-usage-examples/java/{ => sync}/ViewIndex.snippet.example.java (100%) create mode 100755 usage-examples/go/atlas-sdk-go/bluehawkProject.sh create mode 100644 usage-examples/go/atlas-sdk-go/tests/cleanup.go delete mode 100644 usage-examples/go/atlas-sdk-go/utils/utility.go diff --git a/generated-usage-examples/go/atlas-sdk-go/README.md b/generated-usage-examples/go/atlas-sdk-go/README.md new file mode 100644 index 0000000..a9a3106 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/README.md @@ -0,0 +1,25 @@ +```text +atlas-sdk-go/ +│── cmd/ # ✅ Self-contained, runnable scripts +│ ├── get_logs/ # Script to fetch invoices +│ ├── main.go # Script to retrieve logs +│ ├── get_metrics/ # Script to fetch invoices +│ ├── main.go # Script to delete data +│── config/ # ✅ Configuration directory +│ ├── config.json # General app settings (non-sensitive) +│── internal/ # ✅ Shared internal logic +│ ├── config_loader.go # Loads JSON configs +│ ├── secrets_loader.go # Loads secrets securely +│── .gitignore # Exclude secrets.json +│── go.mod # Go module file +│── go.sum # Dependency checksums +│── README.md # Documentation + + +```shell +./bluehawk.sh +``` + +```shell +./run_cmd.sh get_logs +``` diff --git a/generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go b/generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go new file mode 100644 index 0000000..ba54fae --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go @@ -0,0 +1,95 @@ +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" +) + +const ( + LogName = "mongodb" +) + +type GetHostLogsParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + HostName string `json:"hostName"` + LogName string `json:"logName"` // valid values: "mongodb" or "mongos" + EndDate *int64 `json:"endDate,omitempty"` + StartDate *int64 `json:"startDate,omitempty"` +} + +// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. +func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { + fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) + + params := &admin.GetHostLogsApiParams{ + GroupId: hostParams.GroupID, + HostName: hostParams.HostName, + LogName: hostParams.LogName, + StartDate: hostParams.StartDate, + EndDate: hostParams.EndDate, + } + + resp, err := client.GetHostLogs(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get logs: %w", err) + } + defer func() { + if resp != nil { + if closeErr := resp.Close(); closeErr != nil { + log.Printf("Warning: failed to close response body: %v", closeErr) + } + } + }() + + // Create log file with a .gz extension + logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) + logFile, err := os.Create(logFileName) + if err != nil { + return fmt.Errorf("failed to create log file: %w", err) + } + defer func(logFile *os.File) { + if logFile != nil { + if err := logFile.Close(); err != nil { + log.Printf("Warning: failed to close log file: %v", err) + } + } + }(logFile) + + // Write compressed logs to file + if _, err = io.Copy(logFile, resp); err != nil { + return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) + } + fmt.Printf("Logs saved to %s\n", logFileName) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &GetHostLogsParams{ + GroupID: config.AtlasProjectID, + HostName: config.AtlasHostName, // The host to get logs for + LogName: LogName, // The type of log to get ("mongodb" or "mongos") + } + + // Downloads the specified host's MongoDB logs as a .gz file + if err := getHostLogs(ctx, *client, params); err != nil { + fmt.Printf("Error fetching host logs: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go b/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go new file mode 100644 index 0000000..c1c66cc --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go @@ -0,0 +1,112 @@ +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" + "time" +) + +type GetProcessMetricParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + ProcessID string `json:"processId"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +type GetDiskMetricParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + ProcessID string `json:"processId"` + PartitionName string `json:"partitionName"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +// Fetches metrics for a specified host process in a project +func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { + fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) + + params := &admin.GetHostMeasurementsApiParams{ + GroupId: hostParams.GroupID, + ProcessId: hostParams.ProcessID, + Granularity: hostParams.Granularity, + M: hostParams.M, + Period: hostParams.Period, + Start: hostParams.Start, + End: hostParams.End, + } + + resp, err := client.GetProcessMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + + return nil +} + +// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON +func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { + + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: diskParams.GroupID, + ProcessId: diskParams.ProcessID, + PartitionName: diskParams.PartitionName, + Granularity: diskParams.Granularity, + M: diskParams.M, + Period: diskParams.Period, + Start: diskParams.Start, + End: diskParams.End, + } + + resp, err := client.GetDiskMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/configs/config.json b/generated-usage-examples/go/atlas-sdk-go/configs/config.json new file mode 100644 index 0000000..05f5000 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/configs/config.json @@ -0,0 +1,9 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" +} diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go new file mode 100644 index 0000000..bac6689 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go @@ -0,0 +1,50 @@ +package internal + +import ( + "context" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" +) + +type AtlasClient interface { + GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) + GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) + GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) +} + +type HTTPClient struct { + sdk *admin.APIClient +} + +// NewAtlasClient creates a new Atlas API client using the provided SDK client +func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { + return &HTTPClient{sdk: sdk} +} + +// GetHostLogs fetches MongoDB logs for the specified host in your project +func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() + if err != nil { + return nil, err + } + return resp, nil +} + +// GetProcessMetrics fetches metrics for a specified host process in a project +func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + return nil, err + } + return resp, nil +} + +// GetDiskMetrics fetches disk metrics for a specified disk partition in a project +func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + return resp, err + } + return resp, nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go new file mode 100644 index 0000000..0ed9b6c --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go @@ -0,0 +1,49 @@ +package auth + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +const ( + filePath = "./configs/config-prod.json" +) + +// CreateAtlasClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials. +func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { + + secrets, err := internal.LoadSecrets() + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) + } + if err := secrets.CheckRequiredEnv(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) + } + + config, err := internal.LoadConfig(filePath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) + } + config.SetDefaults() + if err := config.CheckRequiredFields(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid config: %w", err) + } + + // Initialize API client using OAuth 2.0 with service account Client Credentials + ctx := context.Background() + sdk, err := admin.NewClient( + admin.UseBaseURL(config.AtlasBaseURL), + admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) + } + + client := internal.NewAtlasClient(sdk) + + return client, secrets, config, nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go new file mode 100644 index 0000000..0ed9b6c --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go @@ -0,0 +1,49 @@ +package auth + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +const ( + filePath = "./configs/config-prod.json" +) + +// CreateAtlasClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials. +func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { + + secrets, err := internal.LoadSecrets() + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) + } + if err := secrets.CheckRequiredEnv(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) + } + + config, err := internal.LoadConfig(filePath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) + } + config.SetDefaults() + if err := config.CheckRequiredFields(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid config: %w", err) + } + + // Initialize API client using OAuth 2.0 with service account Client Credentials + ctx := context.Background() + sdk, err := admin.NewClient( + admin.UseBaseURL(config.AtlasBaseURL), + admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) + } + + client := internal.NewAtlasClient(sdk) + + return client, secrets, config, nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go new file mode 100644 index 0000000..8ff02c6 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go @@ -0,0 +1,67 @@ +package internal + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +type Config struct { + AtlasBaseURL string `json:"ATLAS_BASE_URL"` + AtlasOrgID string `json:"ATLAS_ORG_ID"` + AtlasProjectID string `json:"ATLAS_PROJECT_ID"` + AtlasClusterName string `json:"ATLAS_CLUSTER_NAME"` + AtlasHostName string `json:"ATLAS_HOST_NAME"` + AtlasPort string `json:"ATLAS_PORT"` + AtlasProcessID string `json:"ATLAS_PROCESS_ID"` +} + +// LoadConfig loads a JSON config file to make it available to the application +func LoadConfig(filePath string) (*Config, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("error opening config file: %w", err) + } + defer func(file *os.File) { + err := file.Close() + if err != nil { + fmt.Println("Error closing file") + } + }(file) + + var config Config + decoder := json.NewDecoder(file) + if err := decoder.Decode(&config); err != nil { + return nil, fmt.Errorf("error decoding config file: %w", err) + } + return &config, nil +} + +// SetDefaults sets default values if specified config variables are empty +func (c *Config) SetDefaults() { + if c.AtlasBaseURL == "" { + c.AtlasBaseURL = "https://cloud.mongodb.com" + } + if c.AtlasPort == "" { + c.AtlasPort = "27017" + } + if c.AtlasProcessID == "" && c.AtlasHostName != "" { + c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort + } + if c.AtlasHostName == "" && c.AtlasProcessID != "" { + c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] + } +} + +// CheckRequiredFields verifies that required Atlas fields are set in the config file +func (c *Config) CheckRequiredFields() error { + if c.AtlasOrgID == "" || c.AtlasProjectID == "" { + return fmt.Errorf("missing required Atlas fields in config file") + } + if c.AtlasProcessID == "" || c.AtlasHostName == "" && c.AtlasPort == "" { + return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") + } + return nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go new file mode 100644 index 0000000..0e761b9 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go @@ -0,0 +1,35 @@ + +package internal + +import ( + "fmt" + "github.com/joho/godotenv" + "log" + "os" +) + +type Secrets struct { + ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` + ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` +} + +// LoadSecrets loads environment variables from a .env file to use in the application +func LoadSecrets() (*Secrets, error) { + if err := godotenv.Load("./.env"); err != nil { + log.Println("No .env file found") + } + secrets := &Secrets{ + ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), + ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), + } + return secrets, nil +} + +// CheckRequiredEnv verifies that required environment variables are set in .env +func (s *Secrets) CheckRequiredEnv() error { + if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { + return fmt.Errorf("service account client credentials must be set") + } + return nil +} + diff --git a/generated-usage-examples/go/ann-basic-with-scenario.snippet.example.go b/generated-usage-examples/go/driver/ann-basic-with-scenario.snippet.example.go similarity index 100% rename from generated-usage-examples/go/ann-basic-with-scenario.snippet.example.go rename to generated-usage-examples/go/driver/ann-basic-with-scenario.snippet.example.go diff --git a/generated-usage-examples/go/ann-basic.snippet.example.go b/generated-usage-examples/go/driver/ann-basic.snippet.example.go similarity index 100% rename from generated-usage-examples/go/ann-basic.snippet.example.go rename to generated-usage-examples/go/driver/ann-basic.snippet.example.go diff --git a/generated-usage-examples/go/ann-filter-with-scenario.snippet.example.go b/generated-usage-examples/go/driver/ann-filter-with-scenario.snippet.example.go similarity index 100% rename from generated-usage-examples/go/ann-filter-with-scenario.snippet.example.go rename to generated-usage-examples/go/driver/ann-filter-with-scenario.snippet.example.go diff --git a/generated-usage-examples/go/ann-filter.snippet.example.go b/generated-usage-examples/go/driver/ann-filter.snippet.example.go similarity index 100% rename from generated-usage-examples/go/ann-filter.snippet.example.go rename to generated-usage-examples/go/driver/ann-filter.snippet.example.go diff --git a/generated-usage-examples/go/create-index-basic.snippet.example.go b/generated-usage-examples/go/driver/create-index-basic.snippet.example.go similarity index 100% rename from generated-usage-examples/go/create-index-basic.snippet.example.go rename to generated-usage-examples/go/driver/create-index-basic.snippet.example.go diff --git a/generated-usage-examples/go/create-index-filter.snippet.example.go b/generated-usage-examples/go/driver/create-index-filter.snippet.example.go similarity index 100% rename from generated-usage-examples/go/create-index-filter.snippet.example.go rename to generated-usage-examples/go/driver/create-index-filter.snippet.example.go diff --git a/generated-usage-examples/go/create-index-without-filter-using-scenarios.snippet.example.go b/generated-usage-examples/go/driver/create-index-without-filter-using-scenarios.snippet.example.go similarity index 100% rename from generated-usage-examples/go/create-index-without-filter-using-scenarios.snippet.example.go rename to generated-usage-examples/go/driver/create-index-without-filter-using-scenarios.snippet.example.go diff --git a/generated-usage-examples/go/drop-index.snippet.example.go b/generated-usage-examples/go/driver/drop-index.snippet.example.go similarity index 100% rename from generated-usage-examples/go/drop-index.snippet.example.go rename to generated-usage-examples/go/driver/drop-index.snippet.example.go diff --git a/generated-usage-examples/go/edit-index.snippet.example.go b/generated-usage-examples/go/driver/edit-index.snippet.example.go similarity index 100% rename from generated-usage-examples/go/edit-index.snippet.example.go rename to generated-usage-examples/go/driver/edit-index.snippet.example.go diff --git a/generated-usage-examples/go/enn.snippet.example.go b/generated-usage-examples/go/driver/enn.snippet.example.go similarity index 100% rename from generated-usage-examples/go/enn.snippet.example.go rename to generated-usage-examples/go/driver/enn.snippet.example.go diff --git a/generated-usage-examples/go/view-index.snippet.example.go b/generated-usage-examples/go/driver/view-index.snippet.example.go similarity index 100% rename from generated-usage-examples/go/view-index.snippet.example.go rename to generated-usage-examples/go/driver/view-index.snippet.example.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go b/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go new file mode 100644 index 0000000..ba54fae --- /dev/null +++ b/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go @@ -0,0 +1,95 @@ +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" +) + +const ( + LogName = "mongodb" +) + +type GetHostLogsParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + HostName string `json:"hostName"` + LogName string `json:"logName"` // valid values: "mongodb" or "mongos" + EndDate *int64 `json:"endDate,omitempty"` + StartDate *int64 `json:"startDate,omitempty"` +} + +// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. +func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { + fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) + + params := &admin.GetHostLogsApiParams{ + GroupId: hostParams.GroupID, + HostName: hostParams.HostName, + LogName: hostParams.LogName, + StartDate: hostParams.StartDate, + EndDate: hostParams.EndDate, + } + + resp, err := client.GetHostLogs(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get logs: %w", err) + } + defer func() { + if resp != nil { + if closeErr := resp.Close(); closeErr != nil { + log.Printf("Warning: failed to close response body: %v", closeErr) + } + } + }() + + // Create log file with a .gz extension + logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) + logFile, err := os.Create(logFileName) + if err != nil { + return fmt.Errorf("failed to create log file: %w", err) + } + defer func(logFile *os.File) { + if logFile != nil { + if err := logFile.Close(); err != nil { + log.Printf("Warning: failed to close log file: %v", err) + } + } + }(logFile) + + // Write compressed logs to file + if _, err = io.Copy(logFile, resp); err != nil { + return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) + } + fmt.Printf("Logs saved to %s\n", logFileName) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &GetHostLogsParams{ + GroupID: config.AtlasProjectID, + HostName: config.AtlasHostName, // The host to get logs for + LogName: LogName, // The type of log to get ("mongodb" or "mongos") + } + + // Downloads the specified host's MongoDB logs as a .gz file + if err := getHostLogs(ctx, *client, params); err != nil { + fmt.Printf("Error fetching host logs: %v", err) + } +} + diff --git a/generated-usage-examples/go/sdk/main.snippet.get-logs-main.go b/generated-usage-examples/go/sdk/main.snippet.get-logs-main.go new file mode 100644 index 0000000..5c89873 --- /dev/null +++ b/generated-usage-examples/go/sdk/main.snippet.get-logs-main.go @@ -0,0 +1,21 @@ +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &GetHostLogsParams{ + GroupID: config.AtlasProjectID, + HostName: config.AtlasHostName, // The host to get logs for + LogName: LogName, // The type of log to get ("mongodb" or "mongos") + } + + // Downloads the specified host's MongoDB logs as a .gz file + if err := getHostLogs(ctx, *client, params); err != nil { + fmt.Printf("Error fetching host logs: %v", err) + } +} + diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go b/generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go new file mode 100644 index 0000000..953fa73 --- /dev/null +++ b/generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go @@ -0,0 +1,132 @@ +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" + "time" +) + +type GetProcessMetricParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + ProcessID string `json:"processId"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +type GetDiskMetricParams struct { + GroupID string `json:"groupId"` // Note: GroupID == ProjectID + ProcessID string `json:"processId"` + PartitionName string `json:"partitionName"` + Granularity *string `json:"granularity"` + M *[]string `json:"metrics,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` +} + +// Fetches metrics for a specified host process in a project +func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { + fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) + + params := &admin.GetHostMeasurementsApiParams{ + GroupId: hostParams.GroupID, + ProcessId: hostParams.ProcessID, + Granularity: hostParams.Granularity, + M: hostParams.M, + Period: hostParams.Period, + Start: hostParams.Start, + End: hostParams.End, + } + + resp, err := client.GetProcessMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + + return nil +} + +// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON +func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { + + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: diskParams.GroupID, + ProcessId: diskParams.ProcessID, + PartitionName: diskParams.PartitionName, + Granularity: diskParams.Granularity, + M: diskParams.M, + Period: diskParams.Period, + Start: diskParams.Start, + End: diskParams.End, + } + + resp, err := client.GetDiskMetrics(ctx, params) + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get measurements: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) + } + + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + // Fetch process metrics using the following parameters + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + getProcessMetricParams := &GetProcessMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: config.AtlasProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go b/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go new file mode 100644 index 0000000..d76d0b7 --- /dev/null +++ b/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go @@ -0,0 +1,30 @@ +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + // Fetch process metrics using the following parameters + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + getProcessMetricParams := &GetProcessMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: config.AtlasProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go b/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go new file mode 100644 index 0000000..d76d0b7 --- /dev/null +++ b/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go @@ -0,0 +1,30 @@ +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + // Fetch process metrics using the following parameters + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + getProcessMetricParams := &GetProcessMetricParams{ + GroupID: config.AtlasProjectID, + ProcessID: config.AtlasProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/java/AnnQueryBasic.snippet.example.java b/generated-usage-examples/java/sync/AnnQueryBasic.snippet.example.java similarity index 100% rename from generated-usage-examples/java/AnnQueryBasic.snippet.example.java rename to generated-usage-examples/java/sync/AnnQueryBasic.snippet.example.java diff --git a/generated-usage-examples/java/AnnQueryFilter.snippet.example.java b/generated-usage-examples/java/sync/AnnQueryFilter.snippet.example.java similarity index 100% rename from generated-usage-examples/java/AnnQueryFilter.snippet.example.java rename to generated-usage-examples/java/sync/AnnQueryFilter.snippet.example.java diff --git a/generated-usage-examples/java/CreateIndexBasic.snippet.example.java b/generated-usage-examples/java/sync/CreateIndexBasic.snippet.example.java similarity index 100% rename from generated-usage-examples/java/CreateIndexBasic.snippet.example.java rename to generated-usage-examples/java/sync/CreateIndexBasic.snippet.example.java diff --git a/generated-usage-examples/java/CreateIndexFilter.snippet.example.java b/generated-usage-examples/java/sync/CreateIndexFilter.snippet.example.java similarity index 100% rename from generated-usage-examples/java/CreateIndexFilter.snippet.example.java rename to generated-usage-examples/java/sync/CreateIndexFilter.snippet.example.java diff --git a/generated-usage-examples/java/DropIndex.snippet.example.java b/generated-usage-examples/java/sync/DropIndex.snippet.example.java similarity index 100% rename from generated-usage-examples/java/DropIndex.snippet.example.java rename to generated-usage-examples/java/sync/DropIndex.snippet.example.java diff --git a/generated-usage-examples/java/ViewIndex.snippet.example.java b/generated-usage-examples/java/sync/ViewIndex.snippet.example.java similarity index 100% rename from generated-usage-examples/java/ViewIndex.snippet.example.java rename to generated-usage-examples/java/sync/ViewIndex.snippet.example.java diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index a9a3106..ccef4d4 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -1,25 +1,26 @@ +# Atlas SDK for Go + +## Project Structure ```text atlas-sdk-go/ -│── cmd/ # ✅ Self-contained, runnable scripts -│ ├── get_logs/ # Script to fetch invoices -│ ├── main.go # Script to retrieve logs -│ ├── get_metrics/ # Script to fetch invoices -│ ├── main.go # Script to delete data -│── config/ # ✅ Configuration directory -│ ├── config.json # General app settings (non-sensitive) -│── internal/ # ✅ Shared internal logic -│ ├── config_loader.go # Loads JSON configs -│ ├── secrets_loader.go # Loads secrets securely -│── .gitignore # Exclude secrets.json -│── go.mod # Go module file -│── go.sum # Dependency checksums -│── README.md # Documentation - - -```shell -./bluehawk.sh +│── cmd/ # Self-contained, runnable scripts +│ ├── get_logs/ +│ ├── main.go # Get Host logs +│ ├── get_metrics/ +│ ├── main.go # Get Process and Disk metrics +│── config/ +│ ├── config.json # Atlas configuration settings +│── internal/ +│ ├── config_loader.go # Loads JSON configs +│ ├── secrets_loader.go # Loads .env securely +│── .env # Secrets file with API keys, database credentials +│── go.mod +│── go.sum +│── README.md ``` +## Runnable Scripts +Run a specific script using `run_cmd.sh`. For example, to run `get_logs/main.go`: ```shell ./run_cmd.sh get_logs ``` diff --git a/usage-examples/go/atlas-sdk-go/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk.sh index f943ba9..71d774f 100755 --- a/usage-examples/go/atlas-sdk-go/bluehawk.sh +++ b/usage-examples/go/atlas-sdk-go/bluehawk.sh @@ -2,13 +2,18 @@ PROJECT=$(git rev-parse --show-toplevel) # This project requires Bluehawking multiple directories so the generated code can be copied to the user-facing `atlas-architecture-center-go-sdk` repo -GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/admin-sdk/config:$PROJECT/usage-examples/go/admin-sdk/scripts:$PROJECT/usage-examples/go/admin-sdk/internal:$PROJECT/usage-examples/go/admin-sdk/types -GENERATED_EXAMPLES=$PROJECT/generated-examples/go/admin-sdk +GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/cmd +GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/sdk # Bluehawk Admin Go SDK examples -echo "Running Bluehawk snip on $GO_SDK_EXAMPLES..." +echo "Running Bluehawk snip on $GO_SDK_EXAMPLES" echo "Extracting snippets to the $GENERATED_EXAMPLES directory" npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" +# Bluehawk with state tags +echo "Running Bluehawk snip on state tags" +npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state dev +npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state prod + # Clean up any .gz log files find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/bluehawkProject.sh b/usage-examples/go/atlas-sdk-go/bluehawkProject.sh new file mode 100755 index 0000000..72626cf --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/bluehawkProject.sh @@ -0,0 +1,45 @@ +#! /bin/bash + +# NOTE: This project serves as the source repo for a customer-facing `atlas-architecture-center-go-sdk` repo, so we +# need to run Bluehawk on multiple directories that need to be copied to the target repo. + +PROJECT=$(git rev-parse --show-toplevel) +GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/ +GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/atlas-sdk-go/ + +# Define an array of source directories/files +SOURCE_PATHS=( + "$GO_SDK_EXAMPLES/cmd/get_logs/" + "$GO_SDK_EXAMPLES/cmd/get_metrics/" + "$GO_SDK_EXAMPLES/internal" + "$GO_SDK_EXAMPLES/internal/auth" + "$GO_SDK_EXAMPLES" +) + +# Define an array of corresponding target directories +TARGET_PATHS=( + "$GENERATED_EXAMPLES/cmd/get_logs/" + "$GENERATED_EXAMPLES/cmd/get_metrics/" + "$GENERATED_EXAMPLES/internal" + "$GENERATED_EXAMPLES/internal/auth" + "$GENERATED_EXAMPLES" +) + +# Run Bluehawk snip on each source path and output to the corresponding target path +for i in "${!SOURCE_PATHS[@]}"; do + # Create the target directory if it doesn't exist + mkdir -p "${TARGET_PATHS[$i]}" + + echo "Running Bluehawk snip on ${SOURCE_PATHS[$i]}..." + echo "Extracting snippets to the ${TARGET_PATHS[$i]} directory" + npx bluehawk snip "${SOURCE_PATHS[$i]}" -o "${TARGET_PATHS[$i]}" +done + +# Copy project files to generated examples directory +mkdir -p "$GENERATED_EXAMPLES/configs" +cp "$GO_SDK_EXAMPLES/configs/config.json" "$GENERATED_EXAMPLES/configs" +cp "$GO_SDK_EXAMPLES/go.*" "$GENERATED_EXAMPLES" +cp "$GO_SDK_EXAMPLES/README.md" "$GENERATED_EXAMPLES" + +# Clean up any .gz log files +find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 1ac0e9b..7760cfa 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -2,9 +2,9 @@ package main import ( - "admin-sdk/internal" - "admin-sdk/internal/auth" - "admin-sdk/utils" + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + test "atlas-sdk-go/tests" // :remove: "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" @@ -29,7 +29,6 @@ type GetHostLogsParams struct { func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) - // Create request params params := &admin.GetHostLogsApiParams{ GroupId: hostParams.GroupID, HostName: hostParams.HostName, @@ -40,7 +39,10 @@ func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *Ge resp, err := client.GetHostLogs(ctx, params) if err != nil { - return fmt.Errorf("failed to fetch logs for host %s in project %s: %w", hostParams.HostName, hostParams.GroupID, err) + if apiError, ok := admin.AsError(err); ok { + return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) + } + return fmt.Errorf("failed to get logs: %w", err) } defer func() { if resp != nil { @@ -78,7 +80,9 @@ func main() { // Create an Atlas client authenticated using OAuth2 with service account credentials client, _, config, err := auth.CreateAtlasClient() - utils.HandleError(err, "Failed to create Atlas client") + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } params := &GetHostLogsParams{ GroupID: config.AtlasProjectID, @@ -87,7 +91,15 @@ func main() { } // Downloads the specified host's MongoDB logs as a .gz file - utils.HandleError(getHostLogs(ctx, *client, params), "Error fetching host logs") + if err := getHostLogs(ctx, *client, params); err != nil { + fmt.Printf("Error fetching host logs: %v", err) + } + // :remove-start: + // Cleanup downloaded files + if err := test.CleanupGzFiles(); err != nil { + log.Printf("Cleanup error: %v", err) + } + // :remove-end: } // :snippet-end: [get-logs-main] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go index 5471cb0..11a5747 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go @@ -2,34 +2,22 @@ package main import ( - "admin-sdk/internal" - "admin-sdk/internal/auth" - "admin-sdk/utils" + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" "context" "encoding/json" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" "time" ) -// Define parameters for the metrics to fetch -const ( - granularity = "P1D" - period = "P1D" - partitionName = "data" -) - -var ( - processMetrics = []string{"DB_DATA_SIZE_TOTAL", "MAX_SYSTEM_MEMORY_AVAILABLE"} - diskMetrics = []string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"} -) - type GetProcessMetricParams struct { GroupID string `json:"groupId"` // Note: GroupID == ProjectID ProcessID string `json:"processId"` - Granularity string `json:"granularity"` + Granularity *string `json:"granularity"` M *[]string `json:"metrics,omitempty"` - Period *string `json:"period,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` Start *time.Time `json:"start,omitempty"` End *time.Time `json:"end,omitempty"` } @@ -38,9 +26,9 @@ type GetDiskMetricParams struct { GroupID string `json:"groupId"` // Note: GroupID == ProjectID ProcessID string `json:"processId"` PartitionName string `json:"partitionName"` - Granularity string `json:"granularity"` + Granularity *string `json:"granularity"` M *[]string `json:"metrics,omitempty"` - Period *string `json:"period,omitempty"` + Period *string `json:"diskMetricsPeriod,omitempty"` Start *time.Time `json:"start,omitempty"` End *time.Time `json:"end,omitempty"` } @@ -52,14 +40,14 @@ func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostPara params := &admin.GetHostMeasurementsApiParams{ GroupId: hostParams.GroupID, ProcessId: hostParams.ProcessID, - Granularity: &hostParams.Granularity, + Granularity: hostParams.Granularity, M: hostParams.M, Period: hostParams.Period, Start: hostParams.Start, End: hostParams.End, } - resp, _, err := client.GetProcessMetrics(ctx, params) + resp, err := client.GetProcessMetrics(ctx, params) if err != nil { if apiError, ok := admin.AsError(err); ok { return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) @@ -80,21 +68,21 @@ func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostPara return nil } -// Fetch metrics for a specified disk partition in a project +// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { params := &admin.GetDiskMeasurementsApiParams{ GroupId: diskParams.GroupID, ProcessId: diskParams.ProcessID, PartitionName: diskParams.PartitionName, - Granularity: &diskParams.Granularity, + Granularity: diskParams.Granularity, M: diskParams.M, Period: diskParams.Period, Start: diskParams.Start, End: diskParams.End, } - resp, _, err := client.GetDiskMetrics(ctx, params) + resp, err := client.GetDiskMetrics(ctx, params) if err != nil { if apiError, ok := admin.AsError(err); ok { return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) @@ -109,41 +97,65 @@ func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams if err != nil { return fmt.Errorf("failed to marshal response: %w", err) } - fmt.Println(string(jsonData)) return nil } -// :snippet-start: get-metrics-main +// :snippet-start: get-metrics-main-dev +// :snippet-start: get-metrics-main-prod func main() { ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials client, _, config, err := auth.CreateAtlasClient() if err != nil { - fmt.Printf("Failed to create Atlas client: %v", err) + log.Fatalf("Failed to create Atlas client: %v", err) + } + // :state-start: prod + // Fetch process metrics using the following parameters + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", } - getProcessMetricParams := &GetProcessMetricParams{ GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, M: &processMetrics, - Granularity: granularity, - Period: admin.PtrString(period), + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } + // :state-end: [prod] + // :state-start: dev + // Fetch disk metrics using the following parameters + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", } - utils.HandleError(getProcessMetrics(ctx, *client, getProcessMetricParams), - "Error fetching host process metrics") getDiskMetricParams := &GetDiskMetricParams{ GroupID: config.AtlasProjectID, ProcessID: config.AtlasProcessID, PartitionName: partitionName, M: &diskMetrics, - Granularity: granularity, - Period: admin.PtrString(period), + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, } - - utils.HandleError(getDiskMetrics(ctx, *client, getDiskMetricParams), - "Error fetching partition disk metrics") + if err := getDiskMetrics(ctx, *client, getDiskMetricParams); err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } + // :state-end: [dev] } -// :snippet-end: [get-metrics-main] +// :snippet-end: [get-metrics-main-dev] +// :snippet-end: [get-metrics-main-prod] // :snippet-end: [get-metrics-full-script] diff --git a/usage-examples/go/atlas-sdk-go/go.mod b/usage-examples/go/atlas-sdk-go/go.mod index 475d942..1a74333 100644 --- a/usage-examples/go/atlas-sdk-go/go.mod +++ b/usage-examples/go/atlas-sdk-go/go.mod @@ -1,4 +1,4 @@ -module admin-sdk +module atlas-sdk-go go 1.24 diff --git a/usage-examples/go/atlas-sdk-go/internal/api_client.go b/usage-examples/go/atlas-sdk-go/internal/api_client.go index 48c88dd..ba7f695 100644 --- a/usage-examples/go/atlas-sdk-go/internal/api_client.go +++ b/usage-examples/go/atlas-sdk-go/internal/api_client.go @@ -5,13 +5,12 @@ import ( "context" "go.mongodb.org/atlas-sdk/v20250219001/admin" "io" - "net/http" ) type AtlasClient interface { GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) - GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) - GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) + GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) + GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) } type HTTPClient struct { @@ -33,21 +32,21 @@ func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsA } // GetProcessMetrics fetches metrics for a specified host process in a project -func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { - resp, r, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() +func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() if err != nil { - return nil, r, err + return nil, err } - return resp, nil, nil + return resp, nil } // GetDiskMetrics fetches disk metrics for a specified disk partition in a project -func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { - resp, r, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() +func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() if err != nil { - return resp, r, err + return resp, err } - return resp, nil, nil + return resp, nil } // :snippet-end: [api-client-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 9246046..3a58aee 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -2,35 +2,36 @@ package auth import ( - "admin-sdk/internal" + "atlas-sdk-go/internal" "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" ) const ( - filePath = "./configs/config.json" + filePath = "./configs/config-prod.json" ) // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { - // Load secrets secrets, err := internal.LoadSecrets() if err != nil { return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) } - - // Check for missing credentials - if secrets.ServiceAccountID == "" || secrets.ServiceAccountSecret == "" { - return nil, nil, nil, fmt.Errorf("missing Atlas client credentials") + if err := secrets.CheckRequiredEnv(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) } - // Load configuration + config, err := internal.LoadConfig(filePath) if err != nil { return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) } + config.SetDefaults() + if err := config.CheckRequiredFields(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid config: %w", err) + } // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() diff --git a/usage-examples/go/atlas-sdk-go/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go index 7c94e19..865d82c 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/config_loader.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "strings" ) type Config struct { @@ -38,34 +39,35 @@ func LoadConfig(filePath string) (*Config, error) { return &config, nil } +// SetDefaults sets default values if specified config variables are empty +func (c *Config) SetDefaults() { + if c.AtlasBaseURL == "" { + c.AtlasBaseURL = "https://cloud.mongodb.com" + } + if c.AtlasPort == "" { + c.AtlasPort = "27017" + } + if c.AtlasProcessID == "" && c.AtlasHostName != "" { + c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort + } + if c.AtlasHostName == "" && c.AtlasProcessID != "" { + c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] + } +} + +// CheckRequiredFields verifies that required Atlas fields are set in the config file +func (c *Config) CheckRequiredFields() error { + if c.AtlasOrgID == "" || c.AtlasProjectID == "" { + return fmt.Errorf("missing required Atlas fields in config file") + } + if c.AtlasProcessID == "" || c.AtlasHostName == "" && c.AtlasPort == "" { + return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") + } + return nil +} + // :snippet-end: [config-loader-function-full-example] // GetConfigFilePath returns the correct config file based on the environment //func (c *Config) GetConfigFilePath(appEnv string) string { // return fmt.Sprintf("configs/config-%s.json", c.AppEnv) //} - -// SetDefaults sets default values if specified config variables are empty -//func (c *Config) SetDefaults() { -// if utils.IsEmptyString(c.AtlasBaseURL) { -// c.AtlasBaseURL = "https://cloud.mongodb.com" -// } -// if utils.IsEmptyString(c.AtlasPort) { -// c.AtlasPort = "27017" -// } -// if utils.IsEmptyString(c.AtlasProcessID) && !utils.IsEmptyString(c.AtlasHostName) { -// c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort -// } -// if utils.IsEmptyString(c.AtlasHostName) { -// c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] -// } -//} -// -//func (c *Config) CheckRequiredFields() error { -// if utils.IsEmptyString(c.AtlasOrgID) || utils.IsEmptyString(c.AtlasProjectID) { -// return fmt.Errorf("missing required Atlas fields in config file") -// } -// if utils.IsEmptyString(c.AtlasProcessID) || utils.IsEmptyString(c.AtlasHostName) && utils.IsEmptyString(c.AtlasPort) { -// return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") -// } -// return nil -//} diff --git a/usage-examples/go/atlas-sdk-go/internal/mocks.go b/usage-examples/go/atlas-sdk-go/internal/mocks.go index 9960a42..b036f01 100644 --- a/usage-examples/go/atlas-sdk-go/internal/mocks.go +++ b/usage-examples/go/atlas-sdk-go/internal/mocks.go @@ -20,7 +20,6 @@ type MockAtlasClient struct { FakeDiskMetricsError error } -// GetHostLogs returns a fake log response or an error. func (m *MockAtlasClient) GetHostLogs(context.Context, *admin.GetHostLogsApiParams) (io.ReadCloser, error) { if m.FakeHostLogsError != nil { return nil, m.FakeHostLogsError diff --git a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go index 0603cc6..4402e25 100644 --- a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go @@ -3,6 +3,7 @@ package internal import ( + "fmt" "github.com/joho/godotenv" "log" "os" @@ -19,7 +20,7 @@ type Secrets struct { // LoadSecrets loads environment variables from a .env file to use in the application func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load(".env"); err != nil { + if err := godotenv.Load("./.env"); err != nil { log.Println("No .env file found") } secrets := &Secrets{ @@ -33,4 +34,12 @@ func LoadSecrets() (*Secrets, error) { return secrets, nil } +// CheckRequiredEnv verifies that required environment variables are set in .env +func (s *Secrets) CheckRequiredEnv() error { + if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { + return fmt.Errorf("service account client credentials must be set") + } + return nil +} + // :snippet-end: [secrets-loader-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/tests/cleanup.go b/usage-examples/go/atlas-sdk-go/tests/cleanup.go new file mode 100644 index 0000000..5418e84 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/tests/cleanup.go @@ -0,0 +1,33 @@ +package test + +import ( + "fmt" + "log" + "os" + "path/filepath" +) + +// deleteFile deletes a specified file +func deleteFile(fileName string) error { + err := os.Remove(fileName) + log.Printf("Deleting file %s", fileName) + if err != nil { + return fmt.Errorf("failed to delete file %s: %w", fileName, err) + } + return nil +} + +// CleanupGzFiles deletes all .gz files in the project root directory +func CleanupGzFiles() error { + projectRoot := "./" // Project root directory + files, err := filepath.Glob(filepath.Join(projectRoot, "*.gz")) + if err != nil { + return fmt.Errorf("failed to find .gz files: %w", err) + } + for _, file := range files { + if err := deleteFile(file); err != nil { + log.Printf("Failed to delete file %s: %v", file, err) + } + } + return nil +} diff --git a/usage-examples/go/atlas-sdk-go/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go index 720ed8c..671cb82 100644 --- a/usage-examples/go/atlas-sdk-go/tests/mock_test.go +++ b/usage-examples/go/atlas-sdk-go/tests/mock_test.go @@ -1,7 +1,7 @@ package test import ( - "admin-sdk/internal" + "atlas-sdk-go/internal" "bytes" "compress/gzip" "context" diff --git a/usage-examples/go/atlas-sdk-go/utils/utility.go b/usage-examples/go/atlas-sdk-go/utils/utility.go deleted file mode 100644 index e3bdee5..0000000 --- a/usage-examples/go/atlas-sdk-go/utils/utility.go +++ /dev/null @@ -1,80 +0,0 @@ -// :snippet-start: utility-functions-full-example -package utils - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "log" - "os" - "strings" - "time" -) - -// LoadEnvWithDefault loads an environment variable or returns a default value if not set. -func LoadEnvWithDefault(key, defaultValue string) string { - value := os.Getenv(key) - if value == "" { - return defaultValue - } - return value -} - -// HandleError logs the error and exits the program. -func HandleError(err error, message string) { - if err != nil { - log.Fatalf("%s: %v", message, err) - } -} - -// FormatResponseAsJSON reads an io.ReadCloser, formats it as pretty JSON, and returns it as a string. -func FormatResponseAsJSON(body io.ReadCloser) (string, error) { - if body == nil { - return "", fmt.Errorf("response body is nil") - } - defer func(body io.ReadCloser) { - err := body.Close() - if err != nil { - HandleError(err, "Error closing body") - } - }(body) - - // Read the body into a buffer - buf := new(bytes.Buffer) - _, err := io.Copy(buf, body) - if err != nil { - return "", fmt.Errorf("failed to read response body: %w", err) - } - - // Convert raw response to JSON - var formattedJSON bytes.Buffer - err = json.Indent(&formattedJSON, buf.Bytes(), "", " ") // Pretty-print JSON - if err != nil { - return "", fmt.Errorf("failed to format response as JSON: %w", err) - } - - return formattedJSON.String(), nil -} - -// IsEmptyString checks if a string is empty or contains only whitespace. -func IsEmptyString(s string) bool { - return strings.TrimSpace(s) == "" -} - -// Retry retries a function up to a specified number of times with a delay between attempts. -func Retry(attempts int, sleep time.Duration, fn func() error) error { - for i := 0; i < attempts; i++ { - if err := fn(); err != nil { - if i >= (attempts - 1) { - return err - } - time.Sleep(sleep) - continue - } - return nil - } - return fmt.Errorf("reached maximum retry attempts") -} - -// :snippet-end: [utility-functions-full-example] From 349c0a1bc5236c92d29fb1d0d37e05757a183c28 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 20 Mar 2025 01:51:46 -0400 Subject: [PATCH 11/22] Add generic config file --- usage-examples/go/atlas-sdk-go/configs/config.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 usage-examples/go/atlas-sdk-go/configs/config.json diff --git a/usage-examples/go/atlas-sdk-go/configs/config.json b/usage-examples/go/atlas-sdk-go/configs/config.json new file mode 100644 index 0000000..05f5000 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/configs/config.json @@ -0,0 +1,9 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" +} From 784b210f1bfde017b4b1d9111c56c175f41207ab Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 20 Mar 2025 09:25:13 -0400 Subject: [PATCH 12/22] Move copier test files to corresponding directories in new IA --- usage-examples/go/{driver => }/newgotestfile.go | 0 usage-examples/go/{driver => }/ohhai_detete_me | 0 usage-examples/go/{driver => }/v22testfile2.go | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename usage-examples/go/{driver => }/newgotestfile.go (100%) rename usage-examples/go/{driver => }/ohhai_detete_me (100%) rename usage-examples/go/{driver => }/v22testfile2.go (100%) diff --git a/usage-examples/go/driver/newgotestfile.go b/usage-examples/go/newgotestfile.go similarity index 100% rename from usage-examples/go/driver/newgotestfile.go rename to usage-examples/go/newgotestfile.go diff --git a/usage-examples/go/driver/ohhai_detete_me b/usage-examples/go/ohhai_detete_me similarity index 100% rename from usage-examples/go/driver/ohhai_detete_me rename to usage-examples/go/ohhai_detete_me diff --git a/usage-examples/go/driver/v22testfile2.go b/usage-examples/go/v22testfile2.go similarity index 100% rename from usage-examples/go/driver/v22testfile2.go rename to usage-examples/go/v22testfile2.go From 8aa1ece83e7e1bb3b1457bb83101d34bd5ea16c2 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 20 Mar 2025 09:51:15 -0400 Subject: [PATCH 13/22] Tidying up --- usage-examples/go/atlas-sdk-go/README.md | 25 +++++++++++-------- usage-examples/go/atlas-sdk-go/bluehawk.sh | 1 - .../go/atlas-sdk-go/cmd/get_logs/main.go | 2 +- .../go/atlas-sdk-go/internal/auth/auth.go | 3 +-- .../go/atlas-sdk-go/internal/config_loader.go | 6 +---- .../go/atlas-sdk-go/tests/mock_test.go | 14 ++++++----- .../atlas-sdk-go/{internal => tests}/mocks.go | 4 +-- 7 files changed, 28 insertions(+), 27 deletions(-) rename usage-examples/go/atlas-sdk-go/{internal => tests}/mocks.go (91%) diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index ccef4d4..5d310f6 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -3,24 +3,29 @@ ## Project Structure ```text atlas-sdk-go/ -│── cmd/ # Self-contained, runnable scripts +│── cmd/ # Self-contained, runnable scripts │ ├── get_logs/ -│ ├── main.go # Get Host logs +│ ├── main.go │ ├── get_metrics/ -│ ├── main.go # Get Process and Disk metrics -│── config/ -│ ├── config.json # Atlas configuration settings -│── internal/ -│ ├── config_loader.go # Loads JSON configs -│ ├── secrets_loader.go # Loads .env securely -│── .env # Secrets file with API keys, database credentials +│ ├── main.go +│── config/ # Atlas configuration settings +│ ├── config.json +│── internal/ # Shared internal logic + │── auth/ + ├── auth.go +│ ├── api_client.go +│ ├── config_loader.go +│ ├── secrets_loader.go +│── .env # Secrets file (excluded from Git) │── go.mod │── go.sum │── README.md ``` ## Runnable Scripts -Run a specific script using `run_cmd.sh`. For example, to run `get_logs/main.go`: +You can run individual scripts using `run_cmd.sh` and specifying the script's action (i.e. the parent directory for the `main.go` you want to run). + +For example, to run `get_logs/main.go`: ```shell ./run_cmd.sh get_logs ``` diff --git a/usage-examples/go/atlas-sdk-go/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk.sh index 71d774f..f20fde7 100755 --- a/usage-examples/go/atlas-sdk-go/bluehawk.sh +++ b/usage-examples/go/atlas-sdk-go/bluehawk.sh @@ -1,7 +1,6 @@ #! /bin/bash PROJECT=$(git rev-parse --show-toplevel) -# This project requires Bluehawking multiple directories so the generated code can be copied to the user-facing `atlas-architecture-center-go-sdk` repo GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/cmd GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/sdk diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 7760cfa..4c8911f 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -95,7 +95,7 @@ func main() { fmt.Printf("Error fetching host logs: %v", err) } // :remove-start: - // Cleanup downloaded files + // NOTE Internal function to clean up any downloaded files if err := test.CleanupGzFiles(); err != nil { log.Printf("Cleanup error: %v", err) } diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 3a58aee..5f22ce9 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -9,7 +9,7 @@ import ( ) const ( - filePath = "./configs/config-prod.json" + filePath = "./configs/config.json" ) // CreateAtlasClient initializes and returns an authenticated Atlas API client @@ -33,7 +33,6 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con return nil, nil, nil, fmt.Errorf("invalid config: %w", err) } - // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() sdk, err := admin.NewClient( admin.UseBaseURL(config.AtlasBaseURL), diff --git a/usage-examples/go/atlas-sdk-go/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go index 865d82c..997f5c4 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/config_loader.go @@ -18,7 +18,7 @@ type Config struct { AtlasProcessID string `json:"ATLAS_PROCESS_ID"` } -// LoadConfig loads a JSON config file to make it available to the application +// LoadConfig loads a JSON config file to make it globally available func LoadConfig(filePath string) (*Config, error) { file, err := os.Open(filePath) if err != nil { @@ -67,7 +67,3 @@ func (c *Config) CheckRequiredFields() error { } // :snippet-end: [config-loader-function-full-example] -// GetConfigFilePath returns the correct config file based on the environment -//func (c *Config) GetConfigFilePath(appEnv string) string { -// return fmt.Sprintf("configs/config-%s.json", c.AppEnv) -//} diff --git a/usage-examples/go/atlas-sdk-go/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go index 671cb82..a975de5 100644 --- a/usage-examples/go/atlas-sdk-go/tests/mock_test.go +++ b/usage-examples/go/atlas-sdk-go/tests/mock_test.go @@ -1,7 +1,6 @@ package test import ( - "atlas-sdk-go/internal" "bytes" "compress/gzip" "context" @@ -31,12 +30,15 @@ func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { assert.NoError(t, err) // Initialize mock client with compressed log data stored in buffer - mockClient := &internal.MockAtlasClient{ + mockClient := &MockAtlasClient{ FakeHostLogsResponse: buf.String(), } + ctx := context.Background() + params := &admin.GetHostLogsApiParams{} + // Call GetHostLogs to download the log.gz file - resp, err := mockClient.GetHostLogs(context.Background(), &admin.GetHostLogsApiParams{}) + resp, err := mockClient.GetHostLogs(ctx, params) assert.NoError(t, err) assert.NotNil(t, resp) @@ -58,7 +60,7 @@ func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { } func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { - mockClient := &internal.MockAtlasClient{ + mockClient := &MockAtlasClient{ FakeHostLogsResponse: testLogResponse, FakeHostLogsError: nil, } @@ -90,7 +92,7 @@ func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { parsedTime, _ := admin.StringToTime(testTimeStamp) parsedTimeValue := float32(100) - mockClient := &internal.MockAtlasClient{ + mockClient := &MockAtlasClient{ FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ Measurements: &[]admin.MetricsMeasurementAtlas{ { @@ -132,7 +134,7 @@ func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { parsedTime, _ := admin.StringToTime(testTimeStamp) parsedTimeValue := float32(500) - mockClient := &internal.MockAtlasClient{ + mockClient := &MockAtlasClient{ FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ Measurements: &[]admin.MetricsMeasurementAtlas{ { diff --git a/usage-examples/go/atlas-sdk-go/internal/mocks.go b/usage-examples/go/atlas-sdk-go/tests/mocks.go similarity index 91% rename from usage-examples/go/atlas-sdk-go/internal/mocks.go rename to usage-examples/go/atlas-sdk-go/tests/mocks.go index b036f01..24d115e 100644 --- a/usage-examples/go/atlas-sdk-go/internal/mocks.go +++ b/usage-examples/go/atlas-sdk-go/tests/mocks.go @@ -1,4 +1,4 @@ -package internal +package test import ( "context" @@ -8,7 +8,7 @@ import ( "strings" ) -// NOTE: We're using mocked tests because Monitoring and Logging functionality requires a dedicated cluster (M10+) +// NOTE: Mocking client because most monitoring, logging, and auditing functionality requires a dedicated cluster (M10+) // MockAtlasClient is a fake implementation of AtlasClient for testing. type MockAtlasClient struct { From 0f380c59d0c0882766d56dadd069356848d3d375 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Thu, 20 Mar 2025 10:09:00 -0400 Subject: [PATCH 14/22] Cleaning up generated-usage-examples directory --- .../go/atlas-sdk-go/README.md | 25 ---- ...auth.snippet.auth-function-full-example.go | 0 .../main.snippet.get-metrics-full-script.go | 112 ------------------ .../go/atlas-sdk-go/{configs => }/config.json | 0 ...pet.config-loader-function-full-example.go | 0 ...nippet.api-client-function-full-example.go | 0 ...auth.snippet.auth-function-full-example.go | 49 -------- .../main.snippet.get-logs-full-script.go | 0 .../main.snippet.get-logs-main.go | 0 .../main.snippet.get-metrics-full-script.go | 0 .../main.snippet.get-metrics-main-dev.go | 0 .../main.snippet.get-metrics-main-prod.go | 0 ...et.secrets-loader-function-full-example.go | 0 .../sdk/main.snippet.get-logs-full-script.go | 95 --------------- usage-examples/go/atlas-sdk-go/bluehawk.sh | 6 +- 15 files changed, 3 insertions(+), 284 deletions(-) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/README.md rename generated-usage-examples/go/atlas-sdk-go/{internal => }/auth.snippet.auth-function-full-example.go (100%) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go rename generated-usage-examples/go/atlas-sdk-go/{configs => }/config.json (100%) rename generated-usage-examples/go/atlas-sdk-go/{internal => }/config_loader.snippet.config-loader-function-full-example.go (100%) rename generated-usage-examples/go/atlas-sdk-go/{internal => example-source-project}/api_client.snippet.api-client-function-full-example.go (100%) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go rename generated-usage-examples/go/atlas-sdk-go/{cmd/get_logs => }/main.snippet.get-logs-full-script.go (100%) rename generated-usage-examples/go/{sdk => atlas-sdk-go}/main.snippet.get-logs-main.go (100%) rename generated-usage-examples/go/{sdk => atlas-sdk-go}/main.snippet.get-metrics-full-script.go (100%) rename generated-usage-examples/go/{sdk => atlas-sdk-go}/main.snippet.get-metrics-main-dev.go (100%) rename generated-usage-examples/go/{sdk => atlas-sdk-go}/main.snippet.get-metrics-main-prod.go (100%) rename generated-usage-examples/go/atlas-sdk-go/{internal => }/secrets_loader.snippet.secrets-loader-function-full-example.go (100%) delete mode 100644 generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go diff --git a/generated-usage-examples/go/atlas-sdk-go/README.md b/generated-usage-examples/go/atlas-sdk-go/README.md deleted file mode 100644 index a9a3106..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/README.md +++ /dev/null @@ -1,25 +0,0 @@ -```text -atlas-sdk-go/ -│── cmd/ # ✅ Self-contained, runnable scripts -│ ├── get_logs/ # Script to fetch invoices -│ ├── main.go # Script to retrieve logs -│ ├── get_metrics/ # Script to fetch invoices -│ ├── main.go # Script to delete data -│── config/ # ✅ Configuration directory -│ ├── config.json # General app settings (non-sensitive) -│── internal/ # ✅ Shared internal logic -│ ├── config_loader.go # Loads JSON configs -│ ├── secrets_loader.go # Loads secrets securely -│── .gitignore # Exclude secrets.json -│── go.mod # Go module file -│── go.sum # Dependency checksums -│── README.md # Documentation - - -```shell -./bluehawk.sh -``` - -```shell -./run_cmd.sh get_logs -``` diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/auth.snippet.auth-function-full-example.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/internal/auth.snippet.auth-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/auth.snippet.auth-function-full-example.go diff --git a/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go b/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go deleted file mode 100644 index c1c66cc..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.snippet.get-metrics-full-script.go +++ /dev/null @@ -1,112 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" - "time" -) - -type GetProcessMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -type GetDiskMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - PartitionName string `json:"partitionName"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -// Fetches metrics for a specified host process in a project -func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { - fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) - - params := &admin.GetHostMeasurementsApiParams{ - GroupId: hostParams.GroupID, - ProcessId: hostParams.ProcessID, - Granularity: hostParams.Granularity, - M: hostParams.M, - Period: hostParams.Period, - Start: hostParams.Start, - End: hostParams.End, - } - - resp, err := client.GetProcessMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get measurements: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - - return nil -} - -// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON -func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { - - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: diskParams.GroupID, - ProcessId: diskParams.ProcessID, - PartitionName: diskParams.PartitionName, - Granularity: diskParams.Granularity, - M: diskParams.M, - Period: diskParams.Period, - Start: diskParams.Start, - End: diskParams.End, - } - - resp, err := client.GetDiskMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get measurements: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/configs/config.json b/generated-usage-examples/go/atlas-sdk-go/config.json similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/configs/config.json rename to generated-usage-examples/go/atlas-sdk-go/config.json diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/internal/config_loader.snippet.config-loader-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/internal/api_client.snippet.api-client-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go deleted file mode 100644 index 0ed9b6c..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/internal/auth/auth.snippet.auth-function-full-example.go +++ /dev/null @@ -1,49 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const ( - filePath = "./configs/config-prod.json" -) - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { - - secrets, err := internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - // Initialize API client using OAuth 2.0 with service account Client Credentials - ctx := context.Background() - sdk, err := admin.NewClient( - admin.UseBaseURL(config.AtlasBaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - client := internal.NewAtlasClient(sdk) - - return client, secrets, config, nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/cmd/get_logs/main.snippet.get-logs-full-script.go rename to generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-logs-main.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go similarity index 100% rename from generated-usage-examples/go/sdk/main.snippet.get-logs-main.go rename to generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go similarity index 100% rename from generated-usage-examples/go/sdk/main.snippet.get-metrics-full-script.go rename to generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go similarity index 100% rename from generated-usage-examples/go/sdk/main.snippet.get-metrics-main-dev.go rename to generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-prod.go similarity index 100% rename from generated-usage-examples/go/sdk/main.snippet.get-metrics-main-prod.go rename to generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-prod.go diff --git a/generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/secrets_loader.snippet.secrets-loader-function-full-example.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/internal/secrets_loader.snippet.secrets-loader-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/secrets_loader.snippet.secrets-loader-function-full-example.go diff --git a/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go b/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go deleted file mode 100644 index ba54fae..0000000 --- a/generated-usage-examples/go/sdk/main.snippet.get-logs-full-script.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" -) - -const ( - LogName = "mongodb" -) - -type GetHostLogsParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - HostName string `json:"hostName"` - LogName string `json:"logName"` // valid values: "mongodb" or "mongos" - EndDate *int64 `json:"endDate,omitempty"` - StartDate *int64 `json:"startDate,omitempty"` -} - -// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. -func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { - fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) - - params := &admin.GetHostLogsApiParams{ - GroupId: hostParams.GroupID, - HostName: hostParams.HostName, - LogName: hostParams.LogName, - StartDate: hostParams.StartDate, - EndDate: hostParams.EndDate, - } - - resp, err := client.GetHostLogs(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get logs: %w", err) - } - defer func() { - if resp != nil { - if closeErr := resp.Close(); closeErr != nil { - log.Printf("Warning: failed to close response body: %v", closeErr) - } - } - }() - - // Create log file with a .gz extension - logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) - logFile, err := os.Create(logFileName) - if err != nil { - return fmt.Errorf("failed to create log file: %w", err) - } - defer func(logFile *os.File) { - if logFile != nil { - if err := logFile.Close(); err != nil { - log.Printf("Warning: failed to close log file: %v", err) - } - } - }(logFile) - - // Write compressed logs to file - if _, err = io.Copy(logFile, resp); err != nil { - return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) - } - fmt.Printf("Logs saved to %s\n", logFileName) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &GetHostLogsParams{ - GroupID: config.AtlasProjectID, - HostName: config.AtlasHostName, // The host to get logs for - LogName: LogName, // The type of log to get ("mongodb" or "mongos") - } - - // Downloads the specified host's MongoDB logs as a .gz file - if err := getHostLogs(ctx, *client, params); err != nil { - fmt.Printf("Error fetching host logs: %v", err) - } -} - diff --git a/usage-examples/go/atlas-sdk-go/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk.sh index f20fde7..a9cc140 100755 --- a/usage-examples/go/atlas-sdk-go/bluehawk.sh +++ b/usage-examples/go/atlas-sdk-go/bluehawk.sh @@ -1,15 +1,15 @@ #! /bin/bash PROJECT=$(git rev-parse --show-toplevel) -GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/cmd -GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/sdk +GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/ +GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/atlas-sdk-go/ # Bluehawk Admin Go SDK examples echo "Running Bluehawk snip on $GO_SDK_EXAMPLES" echo "Extracting snippets to the $GENERATED_EXAMPLES directory" npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" -# Bluehawk with state tags +# Bluehawk with state tag echo "Running Bluehawk snip on state tags" npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state dev npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state prod From a93c66e68d5760f43f63ddc73c8790424928fe7d Mon Sep 17 00:00:00 2001 From: cbullinger Date: Wed, 26 Mar 2025 22:31:38 -0400 Subject: [PATCH 15/22] applying tech review feedback --- .../go/atlas-sdk-go/cmd/get_logs/main.go | 118 +++--- .../go/atlas-sdk-go/cmd/get_metrics/main.go | 111 +++--- .../go/atlas-sdk-go/internal/api_client.go | 100 ++--- .../go/atlas-sdk-go/internal/auth/auth.go | 16 +- .../go/atlas-sdk-go/tests/cleanup.go | 21 +- .../go/atlas-sdk-go/tests/mock_test.go | 341 +++++++++--------- 6 files changed, 354 insertions(+), 353 deletions(-) diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 4c8911f..64a02ff 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -2,75 +2,83 @@ package main import ( - "atlas-sdk-go/internal" "atlas-sdk-go/internal/auth" test "atlas-sdk-go/tests" // :remove: + "compress/gzip" "context" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" "io" "log" "os" + "strings" ) -const ( - LogName = "mongodb" -) - -type GetHostLogsParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - HostName string `json:"hostName"` - LogName string `json:"logName"` // valid values: "mongodb" or "mongos" - EndDate *int64 `json:"endDate,omitempty"` - StartDate *int64 `json:"startDate,omitempty"` +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("Warning: failed to close resource: %v", err) + } + } } // Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. -func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { - fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) +func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { + logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) + fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - params := &admin.GetHostLogsApiParams{ - GroupId: hostParams.GroupID, - HostName: hostParams.HostName, - LogName: hostParams.LogName, - StartDate: hostParams.StartDate, - EndDate: hostParams.EndDate, + if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { + return "", err } - resp, err := client.GetHostLogs(ctx, params) + fmt.Printf("Logs saved to %s\n", logFileName) + return logFileName, nil +} + +func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get logs: %w", err) + return fmt.Errorf("fetch logs: %w", err) } - defer func() { - if resp != nil { - if closeErr := resp.Close(); closeErr != nil { - log.Printf("Warning: failed to close response body: %v", closeErr) - } - } - }() + defer SafeClose(resp) - // Create log file with a .gz extension - logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) - logFile, err := os.Create(logFileName) + file, err := os.Create(filePath) if err != nil { - return fmt.Errorf("failed to create log file: %w", err) + return fmt.Errorf("create %q: %w", filePath, err) } - defer func(logFile *os.File) { - if logFile != nil { - if err := logFile.Close(); err != nil { - log.Printf("Warning: failed to close log file: %v", err) - } - } - }(logFile) + defer SafeClose(file) - // Write compressed logs to file - if _, err = io.Copy(logFile, resp); err != nil { - return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) + if _, err := io.Copy(file, resp); err != nil { + return fmt.Errorf("write to %q: %w", filePath, err) } - fmt.Printf("Logs saved to %s\n", logFileName) + + return nil +} + +func unzipGzFile(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open gz file: %w", err) + } + defer SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("create gzip reader: %w", err) + } + defer SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create destination file: %w", err) + } + defer SafeClose(destFile) + + if _, err := io.Copy(destFile, gzReader); err != nil { + return fmt.Errorf("unzip copy error: %w", err) + } + + fmt.Printf("Unzipped logs to %s\n", destPath) return nil } @@ -84,16 +92,22 @@ func main() { log.Fatalf("Failed to create Atlas client: %v", err) } - params := &GetHostLogsParams{ - GroupID: config.AtlasProjectID, + params := &admin.GetHostLogsApiParams{ + GroupId: config.AtlasProjectID, HostName: config.AtlasHostName, // The host to get logs for - LogName: LogName, // The type of log to get ("mongodb" or "mongos") + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") } - // Downloads the specified host's MongoDB logs as a .gz file - if err := getHostLogs(ctx, *client, params); err != nil { - fmt.Printf("Error fetching host logs: %v", err) + logFileName, err := getHostLogs(ctx, *client, params) + if err != nil { + log.Fatalf("Failed to download logs: %v", err) + } + + plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" + if err := unzipGzFile(logFileName, plainTextLog); err != nil { + log.Fatalf("Failed to unzip log file: %v", err) } + // :remove-start: // NOTE Internal function to clean up any downloaded files if err := test.CleanupGzFiles(); err != nil { diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go index 11a5747..54ed5d5 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go @@ -2,103 +2,80 @@ package main import ( - "atlas-sdk-go/internal" "atlas-sdk-go/internal/auth" "context" "encoding/json" "fmt" "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" - "time" ) -type GetProcessMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -type GetDiskMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - PartitionName string `json:"partitionName"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - // Fetches metrics for a specified host process in a project -func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { - fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) - - params := &admin.GetHostMeasurementsApiParams{ - GroupId: hostParams.GroupID, - ProcessId: hostParams.ProcessID, - Granularity: hostParams.Granularity, - M: hostParams.M, - Period: hostParams.Period, - Start: hostParams.Start, - End: hostParams.End, +func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + fmt.Printf("Fetching metrics for process %s in project %s", params.ProcessId, params.GroupId) + + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: params.GroupId, + ProcessId: params.ProcessId, + Granularity: params.Granularity, + M: params.M, + Period: params.Period, + Start: params.Start, + End: params.End, } - resp, err := client.GetProcessMetrics(ctx, params) + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, hostMeasurementsParams).Execute() if err != nil { if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) + return nil, fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) } - return fmt.Errorf("failed to get measurements: %w", err) + return nil, fmt.Errorf("failed to get measurements: %w", err) } if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) + return nil, fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) } jsonData, err := json.MarshalIndent(resp, "", " ") if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) + return nil, fmt.Errorf("failed to marshal response: %w", err) } fmt.Println(string(jsonData)) - return nil + return resp, nil } // Fetch metrics for a specified disk partition in a project and print the results to the console as JSON -func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { - - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: diskParams.GroupID, - ProcessId: diskParams.ProcessID, - PartitionName: diskParams.PartitionName, - Granularity: diskParams.Granularity, - M: diskParams.M, - Period: diskParams.Period, - Start: diskParams.Start, - End: diskParams.End, +func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + diskMeasurementParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: params.GroupId, + ProcessId: params.ProcessId, + PartitionName: params.PartitionName, + Granularity: params.Granularity, + M: params.M, + Period: params.Period, + Start: params.Start, + End: params.End, } - resp, err := client.GetDiskMetrics(ctx, params) + resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, diskMeasurementParams).Execute() if err != nil { if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) + return nil, fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) } - return fmt.Errorf("failed to get measurements: %w", err) + return nil, fmt.Errorf("failed to get measurements: %w", err) } if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) + return nil, fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) } jsonData, err := json.MarshalIndent(resp, "", " ") if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) + return nil, fmt.Errorf("failed to marshal response: %w", err) } fmt.Println(string(jsonData)) - return nil + return resp, nil } // :snippet-start: get-metrics-main-dev @@ -107,7 +84,7 @@ func main() { ctx := context.Background() // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() + atlasClient, _, config, err := auth.CreateAtlasClient() if err != nil { log.Fatalf("Failed to create Atlas client: %v", err) } @@ -122,14 +99,15 @@ func main() { "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", } - getProcessMetricParams := &GetProcessMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: config.AtlasProcessID, + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.AtlasProjectID, + ProcessId: config.AtlasProcessID, M: &processMetrics, Granularity: processMetricGranularity, Period: processMetricPeriod, } - if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { fmt.Printf("Error fetching host process metrics: %v", err) } // :state-end: [prod] @@ -142,15 +120,16 @@ func main() { "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", } - getDiskMetricParams := &GetDiskMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: config.AtlasProcessID, + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.AtlasProjectID, + ProcessId: config.AtlasProcessID, PartitionName: partitionName, M: &diskMetrics, Granularity: diskMetricsGranularity, Period: diskMetricsPeriod, } - if err := getDiskMetrics(ctx, *client, getDiskMetricParams); err != nil { + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { fmt.Printf("Error fetching disk metrics: %v", err) } // :state-end: [dev] diff --git a/usage-examples/go/atlas-sdk-go/internal/api_client.go b/usage-examples/go/atlas-sdk-go/internal/api_client.go index ba7f695..97f7b5f 100644 --- a/usage-examples/go/atlas-sdk-go/internal/api_client.go +++ b/usage-examples/go/atlas-sdk-go/internal/api_client.go @@ -1,52 +1,52 @@ -// :snippet-start: api-client-function-full-example package internal -import ( - "context" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" -) - -type AtlasClient interface { - GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) - GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) - GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) -} - -type HTTPClient struct { - sdk *admin.APIClient -} - -// NewAtlasClient creates a new Atlas API client using the provided SDK client -func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { - return &HTTPClient{sdk: sdk} -} - -// GetHostLogs fetches MongoDB logs for the specified host in your project -func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return nil, err - } - return resp, nil -} - -// GetProcessMetrics fetches metrics for a specified host process in a project -func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - return nil, err - } - return resp, nil -} - -// GetDiskMetrics fetches disk metrics for a specified disk partition in a project -func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - return resp, err - } - return resp, nil -} - -// :snippet-end: [api-client-function-full-example] +// +//import ( +// "context" +// "go.mongodb.org/atlas-sdk/v20250219001/admin" +// "io" +//) +// +//type AtlasClient interface { +// GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) +// GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) +// GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) +//} +// +//type HTTPClient struct { +// sdk *admin.APIClient +//} +// +//// NewAtlasClient creates a new Atlas API client using the provided SDK client +//func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { +// return &HTTPClient{sdk: sdk} +//} +// +//// GetHostLogs fetches MongoDB logs for the specified host in your project +//func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { +// resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() +// if err != nil { +// return nil, err +// } +// return resp, nil +//} +// +//// GetProcessMetrics fetches metrics for a specified host process in a project +//func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { +// resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() +// if err != nil { +// return nil, err +// } +// return resp, nil +//} +// +//// GetDiskMetrics fetches disk metrics for a specified disk partition in a project +//func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { +// resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() +// if err != nil { +// return resp, err +// } +// return resp, nil +//} +// +//// :snippet-end: [api-client-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 5f22ce9..9fa7007 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -8,15 +8,15 @@ import ( "go.mongodb.org/atlas-sdk/v20250219001/admin" ) -const ( - filePath = "./configs/config.json" -) +const filePath = "./configs/ignoreme.json" + +// TODO: Update this path ./configs/config.json // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. -func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { +func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - secrets, err := internal.LoadSecrets() + var secrets, err = internal.LoadSecrets() if err != nil { return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) } @@ -34,7 +34,7 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con } ctx := context.Background() - sdk, err := admin.NewClient( + atlasClient, err := admin.NewClient( admin.UseBaseURL(config.AtlasBaseURL), admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), ) @@ -42,9 +42,7 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) } - client := internal.NewAtlasClient(sdk) - - return client, secrets, config, nil + return atlasClient, secrets, config, nil } // :snippet-end: [auth-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/tests/cleanup.go b/usage-examples/go/atlas-sdk-go/tests/cleanup.go index 5418e84..7812373 100644 --- a/usage-examples/go/atlas-sdk-go/tests/cleanup.go +++ b/usage-examples/go/atlas-sdk-go/tests/cleanup.go @@ -19,15 +19,24 @@ func deleteFile(fileName string) error { // CleanupGzFiles deletes all .gz files in the project root directory func CleanupGzFiles() error { - projectRoot := "./" // Project root directory - files, err := filepath.Glob(filepath.Join(projectRoot, "*.gz")) - if err != nil { - return fmt.Errorf("failed to find .gz files: %w", err) + projectRoot := "./" + var filesToDelete []string + + for _, pattern := range []string{"*.gz", "*.log"} { + files, err := filepath.Glob(filepath.Join(projectRoot, pattern)) + if err != nil { + return fmt.Errorf("failed to glob %q: %w", pattern, err) + } + filesToDelete = append(filesToDelete, files...) } - for _, file := range files { - if err := deleteFile(file); err != nil { + + for _, file := range filesToDelete { + if err := os.Remove(file); err != nil { log.Printf("Failed to delete file %s: %v", file, err) + } else { + log.Printf("Deleted %s", file) } } + return nil } diff --git a/usage-examples/go/atlas-sdk-go/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go index a975de5..3ddba09 100644 --- a/usage-examples/go/atlas-sdk-go/tests/mock_test.go +++ b/usage-examples/go/atlas-sdk-go/tests/mock_test.go @@ -1,172 +1,173 @@ package test -import ( - "bytes" - "compress/gzip" - "context" - "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "testing" -) - -var ( - testGroupID = "test-group-id" - testHostName = "test-host-name" - testProcessID = "test-process-id" - testLogName = "mongodb" - testTimeStamp = "2023-01-01T00:00:00Z" - testPartition = "data" - testLogResponse = "log content" -) - -func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { - // Set up a Gzip.Writer - var buf bytes.Buffer - gz := gzip.NewWriter(&buf) - _, err := gz.Write([]byte(testLogResponse)) - assert.NoError(t, err) - err = gz.Close() - assert.NoError(t, err) - - // Initialize mock client with compressed log data stored in buffer - mockClient := &MockAtlasClient{ - FakeHostLogsResponse: buf.String(), - } - - ctx := context.Background() - params := &admin.GetHostLogsApiParams{} - - // Call GetHostLogs to download the log.gz file - resp, err := mockClient.GetHostLogs(ctx, params) - assert.NoError(t, err) - assert.NotNil(t, resp) - - // Read the downloaded log.gz file - gzReader, err := gzip.NewReader(resp) - assert.NoError(t, err) - defer func(gzReader *gzip.Reader) { - err := gzReader.Close() - if err != nil { - t.Errorf("failed to close gzip reader: %v", err) - } - }(gzReader) - - // Verify compressed data with the original log content - var result bytes.Buffer - _, err = io.Copy(&result, gzReader) - assert.NoError(t, err) - assert.Equal(t, testLogResponse, result.String()) -} - -func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { - mockClient := &MockAtlasClient{ - FakeHostLogsResponse: testLogResponse, - FakeHostLogsError: nil, - } - - ctx := context.Background() - params := &admin.GetHostLogsApiParams{ - GroupId: testGroupID, - HostName: testHostName, - LogName: testLogName, - } - - resp, err := mockClient.GetHostLogs(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - ActualLogResponse, err := io.ReadAll(resp) - if err != nil { - t.Fatalf("failed to read log content: %v", err) - } - - if string(ActualLogResponse) != testLogResponse { - t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) - } -} - -func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { - expectedMetricName := "DB_DATA_SIZE_TOTAL" - parsedTime, _ := admin.StringToTime(testTimeStamp) - parsedTimeValue := float32(100) - - mockClient := &MockAtlasClient{ - FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{ - { - Name: admin.PtrString(expectedMetricName), - DataPoints: &[]admin.MetricDataPointAtlas{ - {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, - }, - }, - }, - }, - FakeProcessMetricsError: nil, - } - - ctx := context.Background() - params := &admin.GetHostMeasurementsApiParams{ - GroupId: testGroupID, - ProcessId: testProcessID, - } - - resp, _, err := mockClient.GetProcessMetrics(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if resp.HasMeasurements() == false { - t.Errorf("expected measurements, got none") - } - - measurements := resp.GetMeasurements() - actualMetricName := measurements[0].GetName() - if actualMetricName != expectedMetricName { - t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) - } -} - -func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { - - expectedMetricName := "DISK_PARTITION_SPACE_FREE" - parsedTime, _ := admin.StringToTime(testTimeStamp) - parsedTimeValue := float32(500) - - mockClient := &MockAtlasClient{ - FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{ - { - Name: admin.PtrString(expectedMetricName), - DataPoints: &[]admin.MetricDataPointAtlas{ - {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, - }, - }, - }, - }, - FakeDiskMetricsError: nil, - } - - ctx := context.Background() - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: testGroupID, - ProcessId: testProcessID, - PartitionName: testPartition, - } - - resp, _, err := mockClient.GetDiskMetrics(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if resp.HasMeasurements() == false { - t.Errorf("expected measurements, got none") - } - - measurements := resp.GetMeasurements() - actualMetricName := measurements[0].GetName() - if actualMetricName != expectedMetricName { - t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) - } -} +// +//import ( +// "bytes" +// "compress/gzip" +// "context" +// "github.com/stretchr/testify/assert" +// "go.mongodb.org/atlas-sdk/v20250219001/admin" +// "io" +// "testing" +//) +// +//var ( +// testGroupID = "test-group-id" +// testHostName = "test-host-name" +// testProcessID = "test-process-id" +// testLogName = "mongodb" +// testTimeStamp = "2023-01-01T00:00:00Z" +// testPartition = "data" +// testLogResponse = "log content" +//) +// +//func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { +// // Set up a Gzip.Writer +// var buf bytes.Buffer +// gz := gzip.NewWriter(&buf) +// _, err := gz.Write([]byte(testLogResponse)) +// assert.NoError(t, err) +// err = gz.Close() +// assert.NoError(t, err) +// +// // Initialize mock client with compressed log data stored in buffer +// mockClient := &MockAtlasClient{ +// FakeHostLogsResponse: buf.String(), +// } +// +// ctx := context.Background() +// params := &admin.GetHostLogsApiParams{} +// +// // Call GetHostLogs to download the log.gz file +// resp, err := mockClient.GetHostLogs(ctx, params) +// assert.NoError(t, err) +// assert.NotNil(t, resp) +// +// // Read the downloaded log.gz file +// gzReader, err := gzip.NewReader(resp) +// assert.NoError(t, err) +// defer func(gzReader *gzip.Reader) { +// err := gzReader.Close() +// if err != nil { +// t.Errorf("failed to close gzip reader: %v", err) +// } +// }(gzReader) +// +// // Verify compressed data with the original log content +// var result bytes.Buffer +// _, err = io.Copy(&result, gzReader) +// assert.NoError(t, err) +// assert.Equal(t, testLogResponse, result.String()) +//} +// +//func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { +// mockClient := &MockAtlasClient{ +// FakeHostLogsResponse: testLogResponse, +// FakeHostLogsError: nil, +// } +// +// ctx := context.Background() +// params := &admin.GetHostLogsApiParams{ +// GroupId: testGroupID, +// HostName: testHostName, +// LogName: testLogName, +// } +// +// resp, err := mockClient.GetHostLogs(ctx, params) +// if err != nil { +// t.Fatalf("expected no error, got %v", err) +// } +// +// ActualLogResponse, err := io.ReadAll(resp) +// if err != nil { +// t.Fatalf("failed to read log content: %v", err) +// } +// +// if string(ActualLogResponse) != testLogResponse { +// t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) +// } +//} +// +//func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { +// expectedMetricName := "DB_DATA_SIZE_TOTAL" +// parsedTime, _ := admin.StringToTime(testTimeStamp) +// parsedTimeValue := float32(100) +// +// mockClient := &MockAtlasClient{ +// FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ +// Measurements: &[]admin.MetricsMeasurementAtlas{ +// { +// Name: admin.PtrString(expectedMetricName), +// DataPoints: &[]admin.MetricDataPointAtlas{ +// {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, +// }, +// }, +// }, +// }, +// FakeProcessMetricsError: nil, +// } +// +// ctx := context.Background() +// params := &admin.GetHostMeasurementsApiParams{ +// GroupId: testGroupID, +// ProcessId: testProcessID, +// } +// +// resp, _, err := mockClient.GetProcessMetrics(ctx, params) +// if err != nil { +// t.Fatalf("expected no error, got %v", err) +// } +// +// if resp.HasMeasurements() == false { +// t.Errorf("expected measurements, got none") +// } +// +// measurements := resp.GetMeasurements() +// actualMetricName := measurements[0].GetName() +// if actualMetricName != expectedMetricName { +// t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) +// } +//} +// +//func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { +// +// expectedMetricName := "DISK_PARTITION_SPACE_FREE" +// parsedTime, _ := admin.StringToTime(testTimeStamp) +// parsedTimeValue := float32(500) +// +// mockClient := &MockAtlasClient{ +// FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ +// Measurements: &[]admin.MetricsMeasurementAtlas{ +// { +// Name: admin.PtrString(expectedMetricName), +// DataPoints: &[]admin.MetricDataPointAtlas{ +// {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, +// }, +// }, +// }, +// }, +// FakeDiskMetricsError: nil, +// } +// +// ctx := context.Background() +// params := &admin.GetDiskMeasurementsApiParams{ +// GroupId: testGroupID, +// ProcessId: testProcessID, +// PartitionName: testPartition, +// } +// +// resp, _, err := mockClient.GetDiskMetrics(ctx, params) +// if err != nil { +// t.Fatalf("expected no error, got %v", err) +// } +// +// if resp.HasMeasurements() == false { +// t.Errorf("expected measurements, got none") +// } +// +// measurements := resp.GetMeasurements() +// actualMetricName := measurements[0].GetName() +// if actualMetricName != expectedMetricName { +// t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) +// } +//} From f846f4fd35aa4b355ba7b6bcb5e55eb71c2c00b0 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Fri, 18 Apr 2025 13:51:14 -0400 Subject: [PATCH 16/22] define separate output directories --- config.json | 7 + ...pet.config-loader-function-full-example.go | 67 ---- ...nippet.api-client-function-full-example.go | 50 --- ...auth.snippet.auth-function-full-example.go | 18 +- .../main.snippet.get-logs-full-example.go | 110 ++++++ ...in.snippet.get-metrics-dev-full-example.go | 63 ++++ ...n.snippet.get-metrics-prod-full-example.go | 66 ++++ ...pet.config-loader-function-full-example.go | 57 +++ .../{ => full-example/configs}/config.json | 4 +- .../go/atlas-sdk-go/full-example/go.mod | 17 + .../go/atlas-sdk-go/full-example/go.sum | 20 + ...auth.snippet.auth-function-full-example.go | 45 +++ ...auth.snippet.auth-function-full-example.go | 45 +++ ...pet.config-loader-function-full-example.go | 57 +++ ...et.secrets-loader-function-full-example.go | 0 .../main.snippet.get-logs-full-example.go | 110 ++++++ ...in.snippet.get-metrics-dev-full-example.go | 63 ++++ ...n.snippet.get-metrics-prod-full-example.go | 66 ++++ ...et.secrets-loader-function-full-example.go | 35 ++ .../main.snippet.get-logs-full-script.go | 95 ----- .../main.snippet.get-logs-main.go | 21 -- .../main.snippet.get-metrics-full-script.go | 132 ------- .../main.snippet.get-metrics-main-dev.go | 30 -- .../main.snippet.get-logs-main.go | 27 ++ .../usage-examples/main.snippet.get-logs.go | 111 ++++++ .../main.snippet.get-metrics-dev.go | 64 ++++ .../main.snippet.get-metrics-main-dev.go | 31 ++ .../main.snippet.get-metrics-main-prod.go | 14 +- .../main.snippet.get-metrics-prod.go | 67 ++++ .../usage-examples/snippet.config.json | 7 + usage-examples/go/atlas-sdk-go/README.md | 55 +++ usage-examples/go/atlas-sdk-go/bluehawk.sh | 18 - .../go/atlas-sdk-go/bluehawk/bluehawk.sh | 55 +++ .../atlas-sdk-go/bluehawk/bluehawkProject.sh | 59 +++ .../go/atlas-sdk-go/bluehawkProject.sh | 45 --- .../go/atlas-sdk-go/cmd/get_logs/main.go | 18 +- .../atlas-sdk-go/cmd/get_metrics/dev/main.go | 70 ++++ .../go/atlas-sdk-go/cmd/get_metrics/main.go | 140 ------- .../atlas-sdk-go/cmd/get_metrics/prod/main.go | 73 ++++ .../go/atlas-sdk-go/configs/config.json | 8 +- .../go/atlas-sdk-go/internal/api_client.go | 52 --- .../go/atlas-sdk-go/internal/auth/auth.go | 11 +- .../go/atlas-sdk-go/internal/config_loader.go | 32 +- .../go/atlas-sdk-go/tests/cleanup.go | 6 +- .../go/atlas-sdk-go/tests/mock_test.go | 343 +++++++++--------- usage-examples/go/atlas-sdk-go/tests/mocks.go | 2 +- 46 files changed, 1605 insertions(+), 881 deletions(-) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go rename generated-usage-examples/go/atlas-sdk-go/{ => full-example}/auth.snippet.auth-function-full-example.go (69%) create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go rename generated-usage-examples/go/atlas-sdk-go/{ => full-example/configs}/config.json (58%) create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/go.mod create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/go.sum create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go rename generated-usage-examples/go/atlas-sdk-go/{ => full-example/internal}/secrets_loader.snippet.secrets-loader-function-full-example.go (100%) create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go rename generated-usage-examples/go/atlas-sdk-go/{ => usage-examples}/main.snippet.get-metrics-main-prod.go (72%) create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json delete mode 100755 usage-examples/go/atlas-sdk-go/bluehawk.sh create mode 100755 usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh create mode 100755 usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh delete mode 100755 usage-examples/go/atlas-sdk-go/bluehawkProject.sh create mode 100644 usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go delete mode 100644 usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go create mode 100644 usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go delete mode 100644 usage-examples/go/atlas-sdk-go/internal/api_client.go diff --git a/config.json b/config.json index cd3d0f1..1fe56f7 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,11 @@ [ + { + "notes": "Copy Go project files to Arch Center artifact repo", + "source_directory" : "generated-usage-examples/go/atlas-sdk-go/full-example", + "target_repo" : "atlas-architecture-go-sdk", + "target_branch" : "main", + "target_directory" : "" + }, { "notes": "This is a test config. It can be safely deleted.", "source_directory" : "generated-examples/go", diff --git a/generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go deleted file mode 100644 index 8ff02c6..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/config_loader.snippet.config-loader-function-full-example.go +++ /dev/null @@ -1,67 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "os" - "strings" -) - -type Config struct { - AtlasBaseURL string `json:"ATLAS_BASE_URL"` - AtlasOrgID string `json:"ATLAS_ORG_ID"` - AtlasProjectID string `json:"ATLAS_PROJECT_ID"` - AtlasClusterName string `json:"ATLAS_CLUSTER_NAME"` - AtlasHostName string `json:"ATLAS_HOST_NAME"` - AtlasPort string `json:"ATLAS_PORT"` - AtlasProcessID string `json:"ATLAS_PROCESS_ID"` -} - -// LoadConfig loads a JSON config file to make it available to the application -func LoadConfig(filePath string) (*Config, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Println("Error closing file") - } - }(file) - - var config Config - decoder := json.NewDecoder(file) - if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) - } - return &config, nil -} - -// SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if c.AtlasBaseURL == "" { - c.AtlasBaseURL = "https://cloud.mongodb.com" - } - if c.AtlasPort == "" { - c.AtlasPort = "27017" - } - if c.AtlasProcessID == "" && c.AtlasHostName != "" { - c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort - } - if c.AtlasHostName == "" && c.AtlasProcessID != "" { - c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] - } -} - -// CheckRequiredFields verifies that required Atlas fields are set in the config file -func (c *Config) CheckRequiredFields() error { - if c.AtlasOrgID == "" || c.AtlasProjectID == "" { - return fmt.Errorf("missing required Atlas fields in config file") - } - if c.AtlasProcessID == "" || c.AtlasHostName == "" && c.AtlasPort == "" { - return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") - } - return nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go deleted file mode 100644 index bac6689..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/example-source-project/api_client.snippet.api-client-function-full-example.go +++ /dev/null @@ -1,50 +0,0 @@ -package internal - -import ( - "context" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" -) - -type AtlasClient interface { - GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) - GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) - GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) -} - -type HTTPClient struct { - sdk *admin.APIClient -} - -// NewAtlasClient creates a new Atlas API client using the provided SDK client -func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { - return &HTTPClient{sdk: sdk} -} - -// GetHostLogs fetches MongoDB logs for the specified host in your project -func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return nil, err - } - return resp, nil -} - -// GetProcessMetrics fetches metrics for a specified host process in a project -func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - return nil, err - } - return resp, nil -} - -// GetDiskMetrics fetches disk metrics for a specified disk partition in a project -func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - return resp, err - } - return resp, nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go similarity index 69% rename from generated-usage-examples/go/atlas-sdk-go/auth.snippet.auth-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go index 0ed9b6c..a0e673d 100644 --- a/generated-usage-examples/go/atlas-sdk-go/auth.snippet.auth-function-full-example.go +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go @@ -7,15 +7,14 @@ import ( "go.mongodb.org/atlas-sdk/v20250219001/admin" ) -const ( - filePath = "./configs/config-prod.json" -) +const filePath = "./configs/config.json" + // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. -func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Config, error) { +func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - secrets, err := internal.LoadSecrets() + var secrets, err = internal.LoadSecrets() if err != nil { return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) } @@ -32,18 +31,15 @@ func CreateAtlasClient() (*internal.HTTPClient, *internal.Secrets, *internal.Con return nil, nil, nil, fmt.Errorf("invalid config: %w", err) } - // Initialize API client using OAuth 2.0 with service account Client Credentials ctx := context.Background() - sdk, err := admin.NewClient( - admin.UseBaseURL(config.AtlasBaseURL), + atlasClient, err := admin.NewClient( + admin.UseBaseURL(config.BaseURL), admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), ) if err != nil { return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) } - client := internal.NewAtlasClient(sdk) - - return client, secrets, config, nil + return atlasClient, secrets, config, nil } diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go new file mode 100644 index 0000000..3a4d77f --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go @@ -0,0 +1,110 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "compress/gzip" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" + "strings" +) + +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("Warning: failed to close resource: %v", err) + } + } +} + +// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for +// the specified host in your project. +func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { + logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) + fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) + + if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { + return "", err + } + + fmt.Printf("Logs saved to %s\n", logFileName) + return logFileName, nil +} + +func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() + if err != nil { + return fmt.Errorf("fetch logs: %w", err) + } + defer SafeClose(resp) + + file, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("create %q: %w", filePath, err) + } + defer SafeClose(file) + + if _, err := io.Copy(file, resp); err != nil { + return fmt.Errorf("write to %q: %w", filePath, err) + } + + return nil +} + +func unzipGzFile(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open gz file: %w", err) + } + defer SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("create gzip reader: %w", err) + } + defer SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create destination file: %w", err) + } + defer SafeClose(destFile) + + if _, err := io.Copy(destFile, gzReader); err != nil { + return fmt.Errorf("unzip copy error: %w", err) + } + + fmt.Printf("Unzipped logs to %s\n", destPath) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &admin.GetHostLogsApiParams{ + GroupId: config.ProjectID, + HostName: config.HostName, // The host to get logs for + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + } + + logFileName, err := getHostLogs(ctx, *client, params) + if err != nil { + log.Fatalf("Failed to download logs: %v", err) + } + + plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" + if err := unzipGzFile(logFileName, plainTextLog); err != nil { + log.Fatalf("Failed to unzip log file: %v", err) + } + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go new file mode 100644 index 0000000..fe61acf --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go @@ -0,0 +1,63 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console +func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch disk metrics using the following parameters: + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + } + + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + PartitionName: partitionName, + M: &diskMetrics, + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, + } + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go new file mode 100644 index 0000000..e957167 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go @@ -0,0 +1,66 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console +func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch process metrics using the following parameters: + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go new file mode 100644 index 0000000..44ce33a --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go @@ -0,0 +1,57 @@ +package internal + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +type Config struct { + BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` + OrgID string `json:"ATLAS_ORG_ID"` + ProjectID string `json:"ATLAS_PROJECT_ID"` + ClusterName string `json:"ATLAS_CLUSTER_NAME"` + HostName string + ProcessID string `json:"ATLAS_PROCESS_ID"` +} + +// LoadConfig loads a JSON config file to make it globally available +func LoadConfig(filePath string) (*Config, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("error opening config file: %w", err) + } + defer func(file *os.File) { + err := file.Close() + if err != nil { + fmt.Println("Error closing file") + } + }(file) + + var config Config + decoder := json.NewDecoder(file) + if err := decoder.Decode(&config); err != nil { + return nil, fmt.Errorf("error decoding config file: %w", err) + } + return &config, nil +} + +// SetDefaults sets default values if specified config variables are empty +func (c *Config) SetDefaults() { + if c.BaseURL == "" { + c.BaseURL = "https://cloud.mongodb.com" + } + if c.HostName == "" { + c.HostName = strings.Split(c.ProcessID, ":")[0] + } +} + +// CheckRequiredFields verifies that required Atlas fields are set in the config file +func (c *Config) CheckRequiredFields() error { + if c.OrgID == "" || c.ProjectID == "" { + return fmt.Errorf("missing required Atlas fields in config file") + } + return nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/config.json b/generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json similarity index 58% rename from generated-usage-examples/go/atlas-sdk-go/config.json rename to generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json index 05f5000..65f9e17 100644 --- a/generated-usage-examples/go/atlas-sdk-go/config.json +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json @@ -1,9 +1,7 @@ { - "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", "ATLAS_ORG_ID": "", "ATLAS_PROJECT_ID": "", "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", - "ATLAS_PORT": "27017", "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" } diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod b/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod new file mode 100644 index 0000000..1a74333 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod @@ -0,0 +1,17 @@ +module atlas-sdk-go + +go 1.24 + +require ( + github.com/joho/godotenv v1.5.1 + github.com/stretchr/testify v1.10.0 + go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/mongodb-forks/digest v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum b/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum new file mode 100644 index 0000000..f7ec5e3 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum @@ -0,0 +1,20 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKksrOoc= +github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= +go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go new file mode 100644 index 0000000..a0e673d --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go @@ -0,0 +1,45 @@ +package auth + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +const filePath = "./configs/config.json" + + +// CreateAtlasClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials. +func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { + + var secrets, err = internal.LoadSecrets() + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) + } + if err := secrets.CheckRequiredEnv(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) + } + + config, err := internal.LoadConfig(filePath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) + } + config.SetDefaults() + if err := config.CheckRequiredFields(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid config: %w", err) + } + + ctx := context.Background() + atlasClient, err := admin.NewClient( + admin.UseBaseURL(config.BaseURL), + admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) + } + + return atlasClient, secrets, config, nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go new file mode 100644 index 0000000..a0e673d --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go @@ -0,0 +1,45 @@ +package auth + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +const filePath = "./configs/config.json" + + +// CreateAtlasClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials. +func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { + + var secrets, err = internal.LoadSecrets() + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) + } + if err := secrets.CheckRequiredEnv(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) + } + + config, err := internal.LoadConfig(filePath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) + } + config.SetDefaults() + if err := config.CheckRequiredFields(); err != nil { + return nil, nil, nil, fmt.Errorf("invalid config: %w", err) + } + + ctx := context.Background() + atlasClient, err := admin.NewClient( + admin.UseBaseURL(config.BaseURL), + admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) + } + + return atlasClient, secrets, config, nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go new file mode 100644 index 0000000..44ce33a --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go @@ -0,0 +1,57 @@ +package internal + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +type Config struct { + BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` + OrgID string `json:"ATLAS_ORG_ID"` + ProjectID string `json:"ATLAS_PROJECT_ID"` + ClusterName string `json:"ATLAS_CLUSTER_NAME"` + HostName string + ProcessID string `json:"ATLAS_PROCESS_ID"` +} + +// LoadConfig loads a JSON config file to make it globally available +func LoadConfig(filePath string) (*Config, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("error opening config file: %w", err) + } + defer func(file *os.File) { + err := file.Close() + if err != nil { + fmt.Println("Error closing file") + } + }(file) + + var config Config + decoder := json.NewDecoder(file) + if err := decoder.Decode(&config); err != nil { + return nil, fmt.Errorf("error decoding config file: %w", err) + } + return &config, nil +} + +// SetDefaults sets default values if specified config variables are empty +func (c *Config) SetDefaults() { + if c.BaseURL == "" { + c.BaseURL = "https://cloud.mongodb.com" + } + if c.HostName == "" { + c.HostName = strings.Split(c.ProcessID, ":")[0] + } +} + +// CheckRequiredFields verifies that required Atlas fields are set in the config file +func (c *Config) CheckRequiredFields() error { + if c.OrgID == "" || c.ProjectID == "" { + return fmt.Errorf("missing required Atlas fields in config file") + } + return nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/secrets_loader.snippet.secrets-loader-function-full-example.go rename to generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go new file mode 100644 index 0000000..3a4d77f --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go @@ -0,0 +1,110 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "compress/gzip" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" + "strings" +) + +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("Warning: failed to close resource: %v", err) + } + } +} + +// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for +// the specified host in your project. +func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { + logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) + fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) + + if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { + return "", err + } + + fmt.Printf("Logs saved to %s\n", logFileName) + return logFileName, nil +} + +func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() + if err != nil { + return fmt.Errorf("fetch logs: %w", err) + } + defer SafeClose(resp) + + file, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("create %q: %w", filePath, err) + } + defer SafeClose(file) + + if _, err := io.Copy(file, resp); err != nil { + return fmt.Errorf("write to %q: %w", filePath, err) + } + + return nil +} + +func unzipGzFile(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open gz file: %w", err) + } + defer SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("create gzip reader: %w", err) + } + defer SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create destination file: %w", err) + } + defer SafeClose(destFile) + + if _, err := io.Copy(destFile, gzReader); err != nil { + return fmt.Errorf("unzip copy error: %w", err) + } + + fmt.Printf("Unzipped logs to %s\n", destPath) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &admin.GetHostLogsApiParams{ + GroupId: config.ProjectID, + HostName: config.HostName, // The host to get logs for + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + } + + logFileName, err := getHostLogs(ctx, *client, params) + if err != nil { + log.Fatalf("Failed to download logs: %v", err) + } + + plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" + if err := unzipGzFile(logFileName, plainTextLog); err != nil { + log.Fatalf("Failed to unzip log file: %v", err) + } + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go new file mode 100644 index 0000000..fe61acf --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go @@ -0,0 +1,63 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console +func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch disk metrics using the following parameters: + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + } + + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + PartitionName: partitionName, + M: &diskMetrics, + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, + } + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go new file mode 100644 index 0000000..e957167 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go @@ -0,0 +1,66 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console +func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch process metrics using the following parameters: + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go new file mode 100644 index 0000000..0e761b9 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go @@ -0,0 +1,35 @@ + +package internal + +import ( + "fmt" + "github.com/joho/godotenv" + "log" + "os" +) + +type Secrets struct { + ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` + ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` +} + +// LoadSecrets loads environment variables from a .env file to use in the application +func LoadSecrets() (*Secrets, error) { + if err := godotenv.Load("./.env"); err != nil { + log.Println("No .env file found") + } + secrets := &Secrets{ + ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), + ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), + } + return secrets, nil +} + +// CheckRequiredEnv verifies that required environment variables are set in .env +func (s *Secrets) CheckRequiredEnv() error { + if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { + return fmt.Errorf("service account client credentials must be set") + } + return nil +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go deleted file mode 100644 index ba54fae..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-full-script.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" -) - -const ( - LogName = "mongodb" -) - -type GetHostLogsParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - HostName string `json:"hostName"` - LogName string `json:"logName"` // valid values: "mongodb" or "mongos" - EndDate *int64 `json:"endDate,omitempty"` - StartDate *int64 `json:"startDate,omitempty"` -} - -// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. -func getHostLogs(ctx context.Context, client internal.HTTPClient, hostParams *GetHostLogsParams) error { - fmt.Printf("Fetching %s log for host %s in project %s \n", hostParams.LogName, hostParams.HostName, hostParams.GroupID) - - params := &admin.GetHostLogsApiParams{ - GroupId: hostParams.GroupID, - HostName: hostParams.HostName, - LogName: hostParams.LogName, - StartDate: hostParams.StartDate, - EndDate: hostParams.EndDate, - } - - resp, err := client.GetHostLogs(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to fetch logs for host: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get logs: %w", err) - } - defer func() { - if resp != nil { - if closeErr := resp.Close(); closeErr != nil { - log.Printf("Warning: failed to close response body: %v", closeErr) - } - } - }() - - // Create log file with a .gz extension - logFileName := fmt.Sprintf("logs_%s_%s.gz", hostParams.GroupID, hostParams.HostName) - logFile, err := os.Create(logFileName) - if err != nil { - return fmt.Errorf("failed to create log file: %w", err) - } - defer func(logFile *os.File) { - if logFile != nil { - if err := logFile.Close(); err != nil { - log.Printf("Warning: failed to close log file: %v", err) - } - } - }(logFile) - - // Write compressed logs to file - if _, err = io.Copy(logFile, resp); err != nil { - return fmt.Errorf("failed to write logs to file %s: %w", logFileName, err) - } - fmt.Printf("Logs saved to %s\n", logFileName) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &GetHostLogsParams{ - GroupID: config.AtlasProjectID, - HostName: config.AtlasHostName, // The host to get logs for - LogName: LogName, // The type of log to get ("mongodb" or "mongos") - } - - // Downloads the specified host's MongoDB logs as a .gz file - if err := getHostLogs(ctx, *client, params); err != nil { - fmt.Printf("Error fetching host logs: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go deleted file mode 100644 index 5c89873..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs-main.go +++ /dev/null @@ -1,21 +0,0 @@ -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &GetHostLogsParams{ - GroupID: config.AtlasProjectID, - HostName: config.AtlasHostName, // The host to get logs for - LogName: LogName, // The type of log to get ("mongodb" or "mongos") - } - - // Downloads the specified host's MongoDB logs as a .gz file - if err := getHostLogs(ctx, *client, params); err != nil { - fmt.Printf("Error fetching host logs: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go deleted file mode 100644 index 953fa73..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-full-script.go +++ /dev/null @@ -1,132 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" - "time" -) - -type GetProcessMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -type GetDiskMetricParams struct { - GroupID string `json:"groupId"` // Note: GroupID == ProjectID - ProcessID string `json:"processId"` - PartitionName string `json:"partitionName"` - Granularity *string `json:"granularity"` - M *[]string `json:"metrics,omitempty"` - Period *string `json:"diskMetricsPeriod,omitempty"` - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` -} - -// Fetches metrics for a specified host process in a project -func getProcessMetrics(ctx context.Context, client internal.HTTPClient, hostParams *GetProcessMetricParams) error { - fmt.Printf("Fetching metrics for process %s in project %s", hostParams.ProcessID, hostParams.GroupID) - - params := &admin.GetHostMeasurementsApiParams{ - GroupId: hostParams.GroupID, - ProcessId: hostParams.ProcessID, - Granularity: hostParams.Granularity, - M: hostParams.M, - Period: hostParams.Period, - Start: hostParams.Start, - End: hostParams.End, - } - - resp, err := client.GetProcessMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get measurements: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - - return nil -} - -// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON -func getDiskMetrics(ctx context.Context, client internal.HTTPClient, diskParams *GetDiskMetricParams) error { - - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: diskParams.GroupID, - ProcessId: diskParams.ProcessID, - PartitionName: diskParams.PartitionName, - Granularity: diskParams.Granularity, - M: diskParams.M, - Period: diskParams.Period, - Start: diskParams.Start, - End: diskParams.End, - } - - resp, err := client.GetDiskMetrics(ctx, params) - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return fmt.Errorf("failed to get measurements: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - // Fetch process metrics using the following parameters - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - getProcessMetricParams := &GetProcessMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: config.AtlasProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go deleted file mode 100644 index d76d0b7..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-dev.go +++ /dev/null @@ -1,30 +0,0 @@ -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - // Fetch process metrics using the following parameters - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - getProcessMetricParams := &GetProcessMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: config.AtlasProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go new file mode 100644 index 0000000..cd40582 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go @@ -0,0 +1,27 @@ +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &admin.GetHostLogsApiParams{ + GroupId: config.ProjectID, + HostName: config.HostName, // The host to get logs for + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + } + + logFileName, err := getHostLogs(ctx, *client, params) + if err != nil { + log.Fatalf("Failed to download logs: %v", err) + } + + plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" + if err := unzipGzFile(logFileName, plainTextLog); err != nil { + log.Fatalf("Failed to unzip log file: %v", err) + } + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go new file mode 100644 index 0000000..cfc25f4 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go @@ -0,0 +1,111 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal/auth" + "compress/gzip" + "context" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "log" + "os" + "strings" +) + +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("Warning: failed to close resource: %v", err) + } + } +} + +// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for +// the specified host in your project. +func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { + logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) + fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) + + if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { + return "", err + } + + fmt.Printf("Logs saved to %s\n", logFileName) + return logFileName, nil +} + +func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() + if err != nil { + return fmt.Errorf("fetch logs: %w", err) + } + defer SafeClose(resp) + + file, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("create %q: %w", filePath, err) + } + defer SafeClose(file) + + if _, err := io.Copy(file, resp); err != nil { + return fmt.Errorf("write to %q: %w", filePath, err) + } + + return nil +} + +func unzipGzFile(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open gz file: %w", err) + } + defer SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("create gzip reader: %w", err) + } + defer SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create destination file: %w", err) + } + defer SafeClose(destFile) + + if _, err := io.Copy(destFile, gzReader); err != nil { + return fmt.Errorf("unzip copy error: %w", err) + } + + fmt.Printf("Unzipped logs to %s\n", destPath) + return nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + client, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + params := &admin.GetHostLogsApiParams{ + GroupId: config.ProjectID, + HostName: config.HostName, // The host to get logs for + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + } + + logFileName, err := getHostLogs(ctx, *client, params) + if err != nil { + log.Fatalf("Failed to download logs: %v", err) + } + + plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" + if err := unzipGzFile(logFileName, plainTextLog); err != nil { + log.Fatalf("Failed to unzip log file: %v", err) + } + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go new file mode 100644 index 0000000..95ce8ea --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go @@ -0,0 +1,64 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console +func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch disk metrics using the following parameters: + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + } + + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + PartitionName: partitionName, + M: &diskMetrics, + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, + } + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go new file mode 100644 index 0000000..4cd22c5 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go @@ -0,0 +1,31 @@ +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch disk metrics using the following parameters: + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + } + + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + PartitionName: partitionName, + M: &diskMetrics, + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, + } + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-prod.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go similarity index 72% rename from generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-prod.go rename to generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go index d76d0b7..f07839a 100644 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-main-prod.go +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go @@ -2,11 +2,12 @@ func main() { ctx := context.Background() // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() + atlasClient, _, config, err := auth.CreateAtlasClient() if err != nil { log.Fatalf("Failed to create Atlas client: %v", err) } - // Fetch process metrics using the following parameters + + // Fetch process metrics using the following parameters: processMetricGranularity := admin.PtrString("PT1H") processMetricPeriod := admin.PtrString("P7D") processMetrics := []string{ @@ -16,14 +17,15 @@ func main() { "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", } - getProcessMetricParams := &GetProcessMetricParams{ - GroupID: config.AtlasProjectID, - ProcessID: config.AtlasProcessID, + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, M: &processMetrics, Granularity: processMetricGranularity, Period: processMetricPeriod, } - if err := getProcessMetrics(ctx, *client, getProcessMetricParams); err != nil { + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { fmt.Printf("Error fetching host process metrics: %v", err) } } diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go new file mode 100644 index 0000000..99f27d0 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go @@ -0,0 +1,67 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console +func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch process metrics using the following parameters: + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json b/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json new file mode 100644 index 0000000..65f9e17 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json @@ -0,0 +1,7 @@ +{ + "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" +} diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index 5d310f6..79c1e58 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -1,3 +1,4 @@ +[//]: # (.. Don't Copy to Target Repo ) # Atlas SDK for Go ## Project Structure @@ -29,3 +30,57 @@ For example, to run `get_logs/main.go`: ```shell ./run_cmd.sh get_logs ``` + +## Set up + +### Set environment variables and config file + +1. Create a `.env` file in the root directory with the following environment variables: + ```shell + MONGODB_ATLAS_SERVICE_ACCOUNT_ID=your-service-account-id + MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET=your-service-account-secret + ``` +2. Update the placeholders in the `configs/config.json` file with your Atlas information: + ```json + { + + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" + + } + ``` + > **NOTE: Group ID == Project ID** Groups and projects are synonymous terms. Groups and projects are synonymous terms. Your group id is the same as your project id. +3. + + +--- +scratchpad: +- manually test against real infra +- pull the real data + +PR Push > run on captured data +& scheduled job to validate? (or bump our sdk version along with the v release & +verify; fix any failing test) +- run the gh action locally +--- +1. go sdk testing +2. atlas testing + +we'd need to be notified when either change +we can test sdk automatically with the captured data + +periodic manual validation step to test the infra side +- release cadence for sdk > gh +- release cadence for atlas/infra > server version? api update? +--- +arch center docs versioning considerations +- how to keep arch center version in sync with code example version updates? +--- +snippets in generated-examples > push to arch center repo to use in docs? +--- +narrating out loud the next step? diff --git a/usage-examples/go/atlas-sdk-go/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk.sh deleted file mode 100755 index a9cc140..0000000 --- a/usage-examples/go/atlas-sdk-go/bluehawk.sh +++ /dev/null @@ -1,18 +0,0 @@ -#! /bin/bash - -PROJECT=$(git rev-parse --show-toplevel) -GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/ -GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/atlas-sdk-go/ - -# Bluehawk Admin Go SDK examples -echo "Running Bluehawk snip on $GO_SDK_EXAMPLES" -echo "Extracting snippets to the $GENERATED_EXAMPLES directory" -npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" - -# Bluehawk with state tag -echo "Running Bluehawk snip on state tags" -npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state dev -npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" --state prod - -# Clean up any .gz log files -find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh new file mode 100755 index 0000000..6966e31 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROJECT=$(git rev-parse --show-toplevel) +GO_SDK_EXAMPLES="$PROJECT/usage-examples/go/atlas-sdk-go/" +GENERATED_EXAMPLES="$PROJECT/generated-usage-examples/go/atlas-sdk-go/usage-examples/" + +# ——— helper: run bluehawk and only show the key lines ——— +run_snip() { + local extra_flags="$1" + local label="$2" + local dst="$GENERATED_EXAMPLES" + + echo "→ $label" + npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" +} +# ——— 1) global snippets ——— +run_snip "" "Global snippets" + +# ——— 2) state‑specific snippets ——— +read -p "Do you have any state tags to enter? [y/N]: " resp +if [[ $resp =~ ^[Yy]$ ]]; then + read -a STATES -p "Enter one or more state tags (space‑separated): " + for s in "${STATES[@]}"; do + run_snip "--state $s" "State: $s" + done +else + echo "No state tags — skipping." +fi + +# ——— 3) copy non‑snippable files ——— +# list paths *relative* to $GO_SDK_EXAMPLES +readonly COPY_FILES=( + "configs/config.json" + # add any other JSON (or other) files here… + # DON'T COPY SOURCE README.md +) + +echo "→ Copying raw files (${#COPY_FILES[@]})" +for rel in "${COPY_FILES[@]}"; do + src="$GO_SDK_EXAMPLES/$rel" + dest_dir="$GENERATED_EXAMPLES/" + mkdir -p "$dest_dir" + base=$(basename "$rel") + cp "$src" "$dest_dir/snippet.$base" + echo " • $rel → snippet.$base" +done + +# ——— 4) cleanup ——— + find "$GENERATED_EXAMPLES/" -type f \ + -name '*.snippet.*-full-example.*' \ + -delete -print \ + | sed 's/^/ └ removed: /' + +find "$PROJECT" -name "*.gz" -delete diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh b/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh new file mode 100755 index 0000000..2821680 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +# —— Paths —— +PROJECT=$(git rev-parse --show-toplevel) +SRC_ROOT="$PROJECT/usage-examples/go/atlas-sdk-go" +DST_ROOT="$PROJECT/generated-usage-examples/go/atlas-sdk-go/full-example" + +# —— Helper to run Bluehawk snip and prune nested snippets —— +run_snip() { + local src="$1" dst="$2" label="$3" + + echo "→ $label" + npx bluehawk snip "$src" -o "$dst" \ + + # Remove any snippet files that are NOT the “-full-example” ones + find "$dst" -type f \ + -name '*.snippet.*' \ + ! -name '*.snippet.*-full-example.*' \ + -delete -print \ + | sed 's/^/ └ removed: /' +} + +# —— 1) Snip these source paths into the same relative spot under DST_ROOT —— +SNIP_PATHS=( + "cmd/get_logs" + "cmd/get_metrics" + "internal" + "internal/auth" + "" # root of SRC_ROOT +) + +for rel in "${SNIP_PATHS[@]}"; do + src="$SRC_ROOT/$rel" + dst="$DST_ROOT/$rel" + mkdir -p "$dst" + label="Snip ${rel:-root}" + run_snip "$src" "$dst" "$label" +done + +# —— 2) Copy raw/static files into the same structure —— +## DON'T COPY SOURCE README.md TO TARGET REPO +STATIC_FILES=( + "configs/config.json" + "go.mod" + "go.sum" +) + +echo "→ Copying static files" +for rel in "${STATIC_FILES[@]}"; do + src="$SRC_ROOT/$rel" + dst_dir="$DST_ROOT/$(dirname "$rel")" + mkdir -p "$dst_dir" + cp "$src" "$dst_dir/" + echo " • $rel" +done + +# —— 3) Clean up any .gz logs in the whole project —— +find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/bluehawkProject.sh b/usage-examples/go/atlas-sdk-go/bluehawkProject.sh deleted file mode 100755 index 72626cf..0000000 --- a/usage-examples/go/atlas-sdk-go/bluehawkProject.sh +++ /dev/null @@ -1,45 +0,0 @@ -#! /bin/bash - -# NOTE: This project serves as the source repo for a customer-facing `atlas-architecture-center-go-sdk` repo, so we -# need to run Bluehawk on multiple directories that need to be copied to the target repo. - -PROJECT=$(git rev-parse --show-toplevel) -GO_SDK_EXAMPLES=$PROJECT/usage-examples/go/atlas-sdk-go/ -GENERATED_EXAMPLES=$PROJECT/generated-usage-examples/go/atlas-sdk-go/ - -# Define an array of source directories/files -SOURCE_PATHS=( - "$GO_SDK_EXAMPLES/cmd/get_logs/" - "$GO_SDK_EXAMPLES/cmd/get_metrics/" - "$GO_SDK_EXAMPLES/internal" - "$GO_SDK_EXAMPLES/internal/auth" - "$GO_SDK_EXAMPLES" -) - -# Define an array of corresponding target directories -TARGET_PATHS=( - "$GENERATED_EXAMPLES/cmd/get_logs/" - "$GENERATED_EXAMPLES/cmd/get_metrics/" - "$GENERATED_EXAMPLES/internal" - "$GENERATED_EXAMPLES/internal/auth" - "$GENERATED_EXAMPLES" -) - -# Run Bluehawk snip on each source path and output to the corresponding target path -for i in "${!SOURCE_PATHS[@]}"; do - # Create the target directory if it doesn't exist - mkdir -p "${TARGET_PATHS[$i]}" - - echo "Running Bluehawk snip on ${SOURCE_PATHS[$i]}..." - echo "Extracting snippets to the ${TARGET_PATHS[$i]} directory" - npx bluehawk snip "${SOURCE_PATHS[$i]}" -o "${TARGET_PATHS[$i]}" -done - -# Copy project files to generated examples directory -mkdir -p "$GENERATED_EXAMPLES/configs" -cp "$GO_SDK_EXAMPLES/configs/config.json" "$GENERATED_EXAMPLES/configs" -cp "$GO_SDK_EXAMPLES/go.*" "$GENERATED_EXAMPLES" -cp "$GO_SDK_EXAMPLES/README.md" "$GENERATED_EXAMPLES" - -# Clean up any .gz log files -find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 64a02ff..565f516 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -1,4 +1,6 @@ -// :snippet-start: get-logs-full-script +// :snippet-start: get-logs +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +// :snippet-start: get-logs-full-example package main import ( @@ -22,7 +24,8 @@ func SafeClose(c io.Closer) { } } -// Download a compressed log.gz file that contains the MongoDB logs for the specified host in your project. +// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for +// the specified host in your project. func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) @@ -93,9 +96,9 @@ func main() { } params := &admin.GetHostLogsApiParams{ - GroupId: config.AtlasProjectID, - HostName: config.AtlasHostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + GroupId: config.ProjectID, + HostName: config.HostName, // The host to get logs for + LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") } logFileName, err := getHostLogs(ctx, *client, params) @@ -110,11 +113,12 @@ func main() { // :remove-start: // NOTE Internal function to clean up any downloaded files - if err := test.CleanupGzFiles(); err != nil { + if err := test.CleanupFiles(); err != nil { log.Printf("Cleanup error: %v", err) } // :remove-end: } // :snippet-end: [get-logs-main] -// :snippet-end: [get-logs-full-script] +// :snippet-end: [get-logs-full-example] +// :snippet-end: [get-logs] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go new file mode 100644 index 0000000..1c3987b --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go @@ -0,0 +1,70 @@ +// :snippet-start: get-metrics-dev +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +// :snippet-start: get-metrics-dev-full-example +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console +func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +// :snippet-start: get-metrics-main-dev +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch disk metrics using the following parameters: + partitionName := "data" + diskMetricsGranularity := admin.PtrString("P1D") + diskMetricsPeriod := admin.PtrString("P1D") + diskMetrics := []string{ + "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + } + + diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + PartitionName: partitionName, + M: &diskMetrics, + Granularity: diskMetricsGranularity, + Period: diskMetricsPeriod, + } + _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching disk metrics: %v", err) + } +} + +// :snippet-end: [get-metrics-main-prod] +// :snippet-end: [get-metrics-prod-full-example] +// :snippet-end: [get-metrics-prod] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go deleted file mode 100644 index 54ed5d5..0000000 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/main.go +++ /dev/null @@ -1,140 +0,0 @@ -// :snippet-start: get-metrics-full-script -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// Fetches metrics for a specified host process in a project -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for process %s in project %s", params.ProcessId, params.GroupId) - - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: params.GroupId, - ProcessId: params.ProcessId, - Granularity: params.Granularity, - M: params.M, - Period: params.Period, - Start: params.Start, - End: params.End, - } - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, hostMeasurementsParams).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get measurements for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get measurements: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no measurements found for process %s in project %s", params.ProcessId, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - - return resp, nil -} - -// Fetch metrics for a specified disk partition in a project and print the results to the console as JSON -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - diskMeasurementParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: params.GroupId, - ProcessId: params.ProcessId, - PartitionName: params.PartitionName, - Granularity: params.Granularity, - M: params.M, - Period: params.Period, - Start: params.Start, - End: params.End, - } - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, diskMeasurementParams).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get measurements for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get measurements: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no measurements found for partition %s in project %s", params.PartitionName, params.GroupId) - } - - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -// :snippet-start: get-metrics-main-dev -// :snippet-start: get-metrics-main-prod -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - // :state-start: prod - // Fetch process metrics using the following parameters - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.AtlasProjectID, - ProcessId: config.AtlasProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } - // :state-end: [prod] - // :state-start: dev - // Fetch disk metrics using the following parameters - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.AtlasProjectID, - ProcessId: config.AtlasProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } - // :state-end: [dev] -} - -// :snippet-end: [get-metrics-main-dev] -// :snippet-end: [get-metrics-main-prod] -// :snippet-end: [get-metrics-full-script] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go new file mode 100644 index 0000000..32e18bf --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go @@ -0,0 +1,73 @@ +// :snippet-start: get-metrics-prod +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +// :snippet-start: get-metrics-prod-full-example +package main + +import ( + "atlas-sdk-go/internal/auth" + "context" + "encoding/json" + "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console +func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) + + resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() + if err != nil { + if apiError, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) + } + return nil, fmt.Errorf("failed to get metrics: %w", err) + } + + if resp == nil || resp.HasMeasurements() == false { + return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) + } + jsonData, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal response: %w", err) + } + fmt.Println(string(jsonData)) + return resp, nil +} + +// :snippet-start: get-metrics-main-prod +func main() { + ctx := context.Background() + + // Create an Atlas client authenticated using OAuth2 with service account credentials + atlasClient, _, config, err := auth.CreateAtlasClient() + if err != nil { + log.Fatalf("Failed to create Atlas client: %v", err) + } + + // Fetch process metrics using the following parameters: + processMetricGranularity := admin.PtrString("PT1H") + processMetricPeriod := admin.PtrString("P7D") + processMetrics := []string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + } + hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ + GroupId: config.ProjectID, + ProcessId: config.ProcessID, + M: &processMetrics, + Granularity: processMetricGranularity, + Period: processMetricPeriod, + } + _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + if err != nil { + fmt.Printf("Error fetching host process metrics: %v", err) + } +} + +// :snippet-end: [get-metrics-main-prod] +// :snippet-end: [get-metrics-prod-full-example] +// :snippet-end: [get-metrics-prod] diff --git a/usage-examples/go/atlas-sdk-go/configs/config.json b/usage-examples/go/atlas-sdk-go/configs/config.json index 05f5000..9034951 100644 --- a/usage-examples/go/atlas-sdk-go/configs/config.json +++ b/usage-examples/go/atlas-sdk-go/configs/config.json @@ -1,9 +1,7 @@ { - "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", "ATLAS_ORG_ID": "", "ATLAS_PROJECT_ID": "", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", - "ATLAS_PORT": "27017", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" + "ATLAS_CLUSTER_NAME": "", + "ATLAS_PROCESS_ID": "" } diff --git a/usage-examples/go/atlas-sdk-go/internal/api_client.go b/usage-examples/go/atlas-sdk-go/internal/api_client.go deleted file mode 100644 index 97f7b5f..0000000 --- a/usage-examples/go/atlas-sdk-go/internal/api_client.go +++ /dev/null @@ -1,52 +0,0 @@ -package internal - -// -//import ( -// "context" -// "go.mongodb.org/atlas-sdk/v20250219001/admin" -// "io" -//) -// -//type AtlasClient interface { -// GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) -// GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) -// GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) -//} -// -//type HTTPClient struct { -// sdk *admin.APIClient -//} -// -//// NewAtlasClient creates a new Atlas API client using the provided SDK client -//func NewAtlasClient(sdk *admin.APIClient) *HTTPClient { -// return &HTTPClient{sdk: sdk} -//} -// -//// GetHostLogs fetches MongoDB logs for the specified host in your project -//func (c *HTTPClient) GetHostLogs(ctx context.Context, params *admin.GetHostLogsApiParams) (io.ReadCloser, error) { -// resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() -// if err != nil { -// return nil, err -// } -// return resp, nil -//} -// -//// GetProcessMetrics fetches metrics for a specified host process in a project -//func (c *HTTPClient) GetProcessMetrics(ctx context.Context, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { -// resp, _, err := c.sdk.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() -// if err != nil { -// return nil, err -// } -// return resp, nil -//} -// -//// GetDiskMetrics fetches disk metrics for a specified disk partition in a project -//func (c *HTTPClient) GetDiskMetrics(ctx context.Context, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { -// resp, _, err := c.sdk.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() -// if err != nil { -// return resp, err -// } -// return resp, nil -//} -// -//// :snippet-end: [api-client-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 9fa7007..e666c7b 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -8,9 +8,14 @@ import ( "go.mongodb.org/atlas-sdk/v20250219001/admin" ) -const filePath = "./configs/ignoreme.json" +// :replace-start: { +// "terms": { +// "zz-": "" +// } +// } +const filePath = "./configs/zz-config.json" -// TODO: Update this path ./configs/config.json +// :replace-end: // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. @@ -35,7 +40,7 @@ func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, ctx := context.Background() atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.AtlasBaseURL), + admin.UseBaseURL(config.BaseURL), admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), ) if err != nil { diff --git a/usage-examples/go/atlas-sdk-go/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go index 997f5c4..8a60c9b 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/config_loader.go @@ -9,13 +9,12 @@ import ( ) type Config struct { - AtlasBaseURL string `json:"ATLAS_BASE_URL"` - AtlasOrgID string `json:"ATLAS_ORG_ID"` - AtlasProjectID string `json:"ATLAS_PROJECT_ID"` - AtlasClusterName string `json:"ATLAS_CLUSTER_NAME"` - AtlasHostName string `json:"ATLAS_HOST_NAME"` - AtlasPort string `json:"ATLAS_PORT"` - AtlasProcessID string `json:"ATLAS_PROCESS_ID"` + BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` + OrgID string `json:"ATLAS_ORG_ID"` + ProjectID string `json:"ATLAS_PROJECT_ID"` + ClusterName string `json:"ATLAS_CLUSTER_NAME"` + HostName string + ProcessID string `json:"ATLAS_PROCESS_ID"` } // LoadConfig loads a JSON config file to make it globally available @@ -41,28 +40,19 @@ func LoadConfig(filePath string) (*Config, error) { // SetDefaults sets default values if specified config variables are empty func (c *Config) SetDefaults() { - if c.AtlasBaseURL == "" { - c.AtlasBaseURL = "https://cloud.mongodb.com" + if c.BaseURL == "" { + c.BaseURL = "https://cloud.mongodb.com" } - if c.AtlasPort == "" { - c.AtlasPort = "27017" - } - if c.AtlasProcessID == "" && c.AtlasHostName != "" { - c.AtlasProcessID = c.AtlasHostName + ":" + c.AtlasPort - } - if c.AtlasHostName == "" && c.AtlasProcessID != "" { - c.AtlasHostName = strings.Split(c.AtlasProcessID, ":")[0] + if c.HostName == "" { + c.HostName = strings.Split(c.ProcessID, ":")[0] } } // CheckRequiredFields verifies that required Atlas fields are set in the config file func (c *Config) CheckRequiredFields() error { - if c.AtlasOrgID == "" || c.AtlasProjectID == "" { + if c.OrgID == "" || c.ProjectID == "" { return fmt.Errorf("missing required Atlas fields in config file") } - if c.AtlasProcessID == "" || c.AtlasHostName == "" && c.AtlasPort == "" { - return fmt.Errorf("either ATLAS_PROCESS_ID or ATLAS_HOST_NAME/PORT must be set") - } return nil } diff --git a/usage-examples/go/atlas-sdk-go/tests/cleanup.go b/usage-examples/go/atlas-sdk-go/tests/cleanup.go index 7812373..d8b5f91 100644 --- a/usage-examples/go/atlas-sdk-go/tests/cleanup.go +++ b/usage-examples/go/atlas-sdk-go/tests/cleanup.go @@ -7,7 +7,7 @@ import ( "path/filepath" ) -// deleteFile deletes a specified file +// deleteFile deletes a specified file during cleanup after tests. func deleteFile(fileName string) error { err := os.Remove(fileName) log.Printf("Deleting file %s", fileName) @@ -17,8 +17,8 @@ func deleteFile(fileName string) error { return nil } -// CleanupGzFiles deletes all .gz files in the project root directory -func CleanupGzFiles() error { +// CleanupFiles deletes generated *.gz and *.log files from the project root directory +func CleanupFiles() error { projectRoot := "./" var filesToDelete []string diff --git a/usage-examples/go/atlas-sdk-go/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go index 3ddba09..196d9c3 100644 --- a/usage-examples/go/atlas-sdk-go/tests/mock_test.go +++ b/usage-examples/go/atlas-sdk-go/tests/mock_test.go @@ -1,173 +1,174 @@ package test -// -//import ( -// "bytes" -// "compress/gzip" -// "context" -// "github.com/stretchr/testify/assert" -// "go.mongodb.org/atlas-sdk/v20250219001/admin" -// "io" -// "testing" -//) -// -//var ( -// testGroupID = "test-group-id" -// testHostName = "test-host-name" -// testProcessID = "test-process-id" -// testLogName = "mongodb" -// testTimeStamp = "2023-01-01T00:00:00Z" -// testPartition = "data" -// testLogResponse = "log content" -//) -// -//func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { -// // Set up a Gzip.Writer -// var buf bytes.Buffer -// gz := gzip.NewWriter(&buf) -// _, err := gz.Write([]byte(testLogResponse)) -// assert.NoError(t, err) -// err = gz.Close() -// assert.NoError(t, err) -// -// // Initialize mock client with compressed log data stored in buffer -// mockClient := &MockAtlasClient{ -// FakeHostLogsResponse: buf.String(), -// } -// -// ctx := context.Background() -// params := &admin.GetHostLogsApiParams{} -// -// // Call GetHostLogs to download the log.gz file -// resp, err := mockClient.GetHostLogs(ctx, params) -// assert.NoError(t, err) -// assert.NotNil(t, resp) -// -// // Read the downloaded log.gz file -// gzReader, err := gzip.NewReader(resp) -// assert.NoError(t, err) -// defer func(gzReader *gzip.Reader) { -// err := gzReader.Close() -// if err != nil { -// t.Errorf("failed to close gzip reader: %v", err) -// } -// }(gzReader) -// -// // Verify compressed data with the original log content -// var result bytes.Buffer -// _, err = io.Copy(&result, gzReader) -// assert.NoError(t, err) -// assert.Equal(t, testLogResponse, result.String()) -//} -// -//func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { -// mockClient := &MockAtlasClient{ -// FakeHostLogsResponse: testLogResponse, -// FakeHostLogsError: nil, -// } -// -// ctx := context.Background() -// params := &admin.GetHostLogsApiParams{ -// GroupId: testGroupID, -// HostName: testHostName, -// LogName: testLogName, -// } -// -// resp, err := mockClient.GetHostLogs(ctx, params) -// if err != nil { -// t.Fatalf("expected no error, got %v", err) -// } -// -// ActualLogResponse, err := io.ReadAll(resp) -// if err != nil { -// t.Fatalf("failed to read log content: %v", err) -// } -// -// if string(ActualLogResponse) != testLogResponse { -// t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) -// } -//} -// -//func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { -// expectedMetricName := "DB_DATA_SIZE_TOTAL" -// parsedTime, _ := admin.StringToTime(testTimeStamp) -// parsedTimeValue := float32(100) -// -// mockClient := &MockAtlasClient{ -// FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ -// Measurements: &[]admin.MetricsMeasurementAtlas{ -// { -// Name: admin.PtrString(expectedMetricName), -// DataPoints: &[]admin.MetricDataPointAtlas{ -// {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, -// }, -// }, -// }, -// }, -// FakeProcessMetricsError: nil, -// } -// -// ctx := context.Background() -// params := &admin.GetHostMeasurementsApiParams{ -// GroupId: testGroupID, -// ProcessId: testProcessID, -// } -// -// resp, _, err := mockClient.GetProcessMetrics(ctx, params) -// if err != nil { -// t.Fatalf("expected no error, got %v", err) -// } -// -// if resp.HasMeasurements() == false { -// t.Errorf("expected measurements, got none") -// } -// -// measurements := resp.GetMeasurements() -// actualMetricName := measurements[0].GetName() -// if actualMetricName != expectedMetricName { -// t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) -// } -//} -// -//func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { -// -// expectedMetricName := "DISK_PARTITION_SPACE_FREE" -// parsedTime, _ := admin.StringToTime(testTimeStamp) -// parsedTimeValue := float32(500) -// -// mockClient := &MockAtlasClient{ -// FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ -// Measurements: &[]admin.MetricsMeasurementAtlas{ -// { -// Name: admin.PtrString(expectedMetricName), -// DataPoints: &[]admin.MetricDataPointAtlas{ -// {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, -// }, -// }, -// }, -// }, -// FakeDiskMetricsError: nil, -// } -// -// ctx := context.Background() -// params := &admin.GetDiskMeasurementsApiParams{ -// GroupId: testGroupID, -// ProcessId: testProcessID, -// PartitionName: testPartition, -// } -// -// resp, _, err := mockClient.GetDiskMetrics(ctx, params) -// if err != nil { -// t.Fatalf("expected no error, got %v", err) -// } -// -// if resp.HasMeasurements() == false { -// t.Errorf("expected measurements, got none") -// } -// -// measurements := resp.GetMeasurements() -// actualMetricName := measurements[0].GetName() -// if actualMetricName != expectedMetricName { -// t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) -// } -//} +// TODO Refactor tests using mock data + +import ( + "bytes" + "compress/gzip" + "context" + "github.com/stretchr/testify/assert" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "io" + "testing" +) + +var ( + testGroupID = "test-group-id" + testHostName = "test-host-name" + testProcessID = "test-process-id" + testLogName = "mongodb" + testTimeStamp = "2023-01-01T00:00:00Z" + testPartition = "data" + testLogResponse = "log content" +) + +func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { + // Set up a Gzip.Writer + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + _, err := gz.Write([]byte(testLogResponse)) + assert.NoError(t, err) + err = gz.Close() + assert.NoError(t, err) + + // Initialize mock client with compressed log data stored in buffer + mockClient := &MockAtlasClient{ + FakeHostLogsResponse: buf.String(), + } + + ctx := context.Background() + params := &admin.GetHostLogsApiParams{} + + // Call GetHostLogs to download the log.gz file + resp, err := mockClient.GetHostLogs(ctx, params) + assert.NoError(t, err) + assert.NotNil(t, resp) + + // Read the downloaded log.gz file + gzReader, err := gzip.NewReader(resp) + assert.NoError(t, err) + defer func(gzReader *gzip.Reader) { + err := gzReader.Close() + if err != nil { + t.Errorf("failed to close gzip reader: %v", err) + } + }(gzReader) + + // Verify compressed data with the original log content + var result bytes.Buffer + _, err = io.Copy(&result, gzReader) + assert.NoError(t, err) + assert.Equal(t, testLogResponse, result.String()) +} + +func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { + mockClient := &MockAtlasClient{ + FakeHostLogsResponse: testLogResponse, + FakeHostLogsError: nil, + } + + ctx := context.Background() + params := &admin.GetHostLogsApiParams{ + GroupId: testGroupID, + HostName: testHostName, + LogName: testLogName, + } + + resp, err := mockClient.GetHostLogs(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + ActualLogResponse, err := io.ReadAll(resp) + if err != nil { + t.Fatalf("failed to read log content: %v", err) + } + + if string(ActualLogResponse) != testLogResponse { + t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) + } +} + +func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { + expectedMetricName := "DB_DATA_SIZE_TOTAL" + parsedTime, _ := admin.StringToTime(testTimeStamp) + parsedTimeValue := float32(100) + + mockClient := &MockAtlasClient{ + FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{ + { + Name: admin.PtrString(expectedMetricName), + DataPoints: &[]admin.MetricDataPointAtlas{ + {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, + }, + }, + }, + }, + FakeProcessMetricsError: nil, + } + + ctx := context.Background() + params := &admin.GetHostMeasurementsApiParams{ + GroupId: testGroupID, + ProcessId: testProcessID, + } + + resp, _, err := mockClient.GetProcessMetrics(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if resp.HasMeasurements() == false { + t.Errorf("expected measurements, got none") + } + + measurements := resp.GetMeasurements() + actualMetricName := measurements[0].GetName() + if actualMetricName != expectedMetricName { + t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) + } +} + +func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { + + expectedMetricName := "DISK_PARTITION_SPACE_FREE" + parsedTime, _ := admin.StringToTime(testTimeStamp) + parsedTimeValue := float32(500) + + mockClient := &MockAtlasClient{ + FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{ + { + Name: admin.PtrString(expectedMetricName), + DataPoints: &[]admin.MetricDataPointAtlas{ + {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, + }, + }, + }, + }, + FakeDiskMetricsError: nil, + } + + ctx := context.Background() + params := &admin.GetDiskMeasurementsApiParams{ + GroupId: testGroupID, + ProcessId: testProcessID, + PartitionName: testPartition, + } + + resp, _, err := mockClient.GetDiskMetrics(ctx, params) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if resp.HasMeasurements() == false { + t.Errorf("expected measurements, got none") + } + + measurements := resp.GetMeasurements() + actualMetricName := measurements[0].GetName() + if actualMetricName != expectedMetricName { + t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) + } +} diff --git a/usage-examples/go/atlas-sdk-go/tests/mocks.go b/usage-examples/go/atlas-sdk-go/tests/mocks.go index 24d115e..c24b6ab 100644 --- a/usage-examples/go/atlas-sdk-go/tests/mocks.go +++ b/usage-examples/go/atlas-sdk-go/tests/mocks.go @@ -8,7 +8,7 @@ import ( "strings" ) -// NOTE: Mocking client because most monitoring, logging, and auditing functionality requires a dedicated cluster (M10+) +// TODO Refactor to use generated mock client // MockAtlasClient is a fake implementation of AtlasClient for testing. type MockAtlasClient struct { From bf36e824b2487938144e109ca214ce073bedcfe7 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Mon, 21 Apr 2025 07:45:12 -0400 Subject: [PATCH 17/22] Fix BH copy script --- ...auth.snippet.auth-function-full-example.go | 45 ------- .../main.snippet.get-logs-full-example.go | 110 ----------------- ...in.snippet.get-metrics-dev-full-example.go | 63 ---------- ...n.snippet.get-metrics-prod-full-example.go | 66 ----------- ...pet.config-loader-function-full-example.go | 57 --------- .../full-example/configs/config.json | 7 -- .../go/atlas-sdk-go/full-example/go.mod | 17 --- .../go/atlas-sdk-go/full-example/go.sum | 20 ---- ...auth.snippet.auth-function-full-example.go | 45 ------- ...auth.snippet.auth-function-full-example.go | 45 ------- ...pet.config-loader-function-full-example.go | 57 --------- ...et.secrets-loader-function-full-example.go | 35 ------ .../main.snippet.get-logs-full-example.go | 110 ----------------- ...in.snippet.get-metrics-dev-full-example.go | 63 ---------- ...n.snippet.get-metrics-prod-full-example.go | 66 ----------- ...et.secrets-loader-function-full-example.go | 35 ------ .../main.snippet.get-logs-main.go | 27 ----- .../usage-examples/main.snippet.get-logs.go | 111 ------------------ .../main.snippet.get-metrics-dev.go | 64 ---------- .../main.snippet.get-metrics-main-dev.go | 31 ----- .../main.snippet.get-metrics-main-prod.go | 32 ----- .../main.snippet.get-metrics-prod.go | 67 ----------- .../usage-examples/snippet.config.json | 7 -- usage-examples/go/atlas-sdk-go/README.md | 50 ++++++-- .../atlas-sdk-go/bluehawk/bluehawkProject.sh | 59 ---------- .../go/atlas-sdk-go/bluehawk/copy.sh | 31 +++++ .../bluehawk/{bluehawk.sh => snip.sh} | 0 .../go/atlas-sdk-go/cmd/get_logs/main.go | 24 ++-- .../atlas-sdk-go/cmd/get_metrics/dev/main.go | 4 +- .../atlas-sdk-go/cmd/get_metrics/prod/main.go | 4 +- .../go/atlas-sdk-go/internal/auth/auth.go | 12 +- .../go/atlas-sdk-go/internal/config_loader.go | 3 - .../atlas-sdk-go/internal/secrets_loader.go | 8 +- .../go/atlas-sdk-go/{ => tests}/run_cmd.sh | 0 34 files changed, 92 insertions(+), 1283 deletions(-) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/go.mod delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/go.sum delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json delete mode 100755 usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh create mode 100644 usage-examples/go/atlas-sdk-go/bluehawk/copy.sh rename usage-examples/go/atlas-sdk-go/bluehawk/{bluehawk.sh => snip.sh} (100%) rename usage-examples/go/atlas-sdk-go/{ => tests}/run_cmd.sh (100%) diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go deleted file mode 100644 index a0e673d..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/auth.snippet.auth-function-full-example.go +++ /dev/null @@ -1,45 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const filePath = "./configs/config.json" - - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - - var secrets, err = internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - ctx := context.Background() - atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.BaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - return atlasClient, secrets, config, nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go deleted file mode 100644 index 3a4d77f..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_logs/main.snippet.get-logs-full-example.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "compress/gzip" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" - "strings" -) - -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - -// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for -// the specified host in your project. -func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { - logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) - fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - - if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { - return "", err - } - - fmt.Printf("Logs saved to %s\n", logFileName) - return logFileName, nil -} - -func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return fmt.Errorf("fetch logs: %w", err) - } - defer SafeClose(resp) - - file, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("create %q: %w", filePath, err) - } - defer SafeClose(file) - - if _, err := io.Copy(file, resp); err != nil { - return fmt.Errorf("write to %q: %w", filePath, err) - } - - return nil -} - -func unzipGzFile(srcPath, destPath string) error { - srcFile, err := os.Open(srcPath) - if err != nil { - return fmt.Errorf("open gz file: %w", err) - } - defer SafeClose(srcFile) - - gzReader, err := gzip.NewReader(srcFile) - if err != nil { - return fmt.Errorf("create gzip reader: %w", err) - } - defer SafeClose(gzReader) - - destFile, err := os.Create(destPath) - if err != nil { - return fmt.Errorf("create destination file: %w", err) - } - defer SafeClose(destFile) - - if _, err := io.Copy(destFile, gzReader); err != nil { - return fmt.Errorf("unzip copy error: %w", err) - } - - fmt.Printf("Unzipped logs to %s\n", destPath) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") - } - - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) - } - - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) - } - -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go deleted file mode 100644 index fe61acf..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-dev-full-example.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go deleted file mode 100644 index e957167..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/cmd/get_metrics/main.snippet.get-metrics-prod-full-example.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go deleted file mode 100644 index 44ce33a..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/config_loader.snippet.config-loader-function-full-example.go +++ /dev/null @@ -1,57 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "os" - "strings" -) - -type Config struct { - BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` - OrgID string `json:"ATLAS_ORG_ID"` - ProjectID string `json:"ATLAS_PROJECT_ID"` - ClusterName string `json:"ATLAS_CLUSTER_NAME"` - HostName string - ProcessID string `json:"ATLAS_PROCESS_ID"` -} - -// LoadConfig loads a JSON config file to make it globally available -func LoadConfig(filePath string) (*Config, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Println("Error closing file") - } - }(file) - - var config Config - decoder := json.NewDecoder(file) - if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) - } - return &config, nil -} - -// SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if c.BaseURL == "" { - c.BaseURL = "https://cloud.mongodb.com" - } - if c.HostName == "" { - c.HostName = strings.Split(c.ProcessID, ":")[0] - } -} - -// CheckRequiredFields verifies that required Atlas fields are set in the config file -func (c *Config) CheckRequiredFields() error { - if c.OrgID == "" || c.ProjectID == "" { - return fmt.Errorf("missing required Atlas fields in config file") - } - return nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json b/generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json deleted file mode 100644 index 65f9e17..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/configs/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "", - "ATLAS_PROJECT_ID": "", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" -} diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod b/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod deleted file mode 100644 index 1a74333..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module atlas-sdk-go - -go 1.24 - -require ( - github.com/joho/godotenv v1.5.1 - github.com/stretchr/testify v1.10.0 - go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/mongodb-forks/digest v1.1.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum b/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum deleted file mode 100644 index f7ec5e3..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/go.sum +++ /dev/null @@ -1,20 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKksrOoc= -github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= -go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go deleted file mode 100644 index a0e673d..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth.snippet.auth-function-full-example.go +++ /dev/null @@ -1,45 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const filePath = "./configs/config.json" - - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - - var secrets, err = internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - ctx := context.Background() - atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.BaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - return atlasClient, secrets, config, nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go deleted file mode 100644 index a0e673d..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/auth/auth.snippet.auth-function-full-example.go +++ /dev/null @@ -1,45 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const filePath = "./configs/config.json" - - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - - var secrets, err = internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - ctx := context.Background() - atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.BaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - return atlasClient, secrets, config, nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go deleted file mode 100644 index 44ce33a..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/config_loader.snippet.config-loader-function-full-example.go +++ /dev/null @@ -1,57 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "os" - "strings" -) - -type Config struct { - BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` - OrgID string `json:"ATLAS_ORG_ID"` - ProjectID string `json:"ATLAS_PROJECT_ID"` - ClusterName string `json:"ATLAS_CLUSTER_NAME"` - HostName string - ProcessID string `json:"ATLAS_PROCESS_ID"` -} - -// LoadConfig loads a JSON config file to make it globally available -func LoadConfig(filePath string) (*Config, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Println("Error closing file") - } - }(file) - - var config Config - decoder := json.NewDecoder(file) - if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) - } - return &config, nil -} - -// SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if c.BaseURL == "" { - c.BaseURL = "https://cloud.mongodb.com" - } - if c.HostName == "" { - c.HostName = strings.Split(c.ProcessID, ":")[0] - } -} - -// CheckRequiredFields verifies that required Atlas fields are set in the config file -func (c *Config) CheckRequiredFields() error { - if c.OrgID == "" || c.ProjectID == "" { - return fmt.Errorf("missing required Atlas fields in config file") - } - return nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go deleted file mode 100644 index 0e761b9..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/internal/secrets_loader.snippet.secrets-loader-function-full-example.go +++ /dev/null @@ -1,35 +0,0 @@ - -package internal - -import ( - "fmt" - "github.com/joho/godotenv" - "log" - "os" -) - -type Secrets struct { - ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` - ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` -} - -// LoadSecrets loads environment variables from a .env file to use in the application -func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load("./.env"); err != nil { - log.Println("No .env file found") - } - secrets := &Secrets{ - ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), - ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), - } - return secrets, nil -} - -// CheckRequiredEnv verifies that required environment variables are set in .env -func (s *Secrets) CheckRequiredEnv() error { - if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { - return fmt.Errorf("service account client credentials must be set") - } - return nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go deleted file mode 100644 index 3a4d77f..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-logs-full-example.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "compress/gzip" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" - "strings" -) - -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - -// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for -// the specified host in your project. -func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { - logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) - fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - - if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { - return "", err - } - - fmt.Printf("Logs saved to %s\n", logFileName) - return logFileName, nil -} - -func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return fmt.Errorf("fetch logs: %w", err) - } - defer SafeClose(resp) - - file, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("create %q: %w", filePath, err) - } - defer SafeClose(file) - - if _, err := io.Copy(file, resp); err != nil { - return fmt.Errorf("write to %q: %w", filePath, err) - } - - return nil -} - -func unzipGzFile(srcPath, destPath string) error { - srcFile, err := os.Open(srcPath) - if err != nil { - return fmt.Errorf("open gz file: %w", err) - } - defer SafeClose(srcFile) - - gzReader, err := gzip.NewReader(srcFile) - if err != nil { - return fmt.Errorf("create gzip reader: %w", err) - } - defer SafeClose(gzReader) - - destFile, err := os.Create(destPath) - if err != nil { - return fmt.Errorf("create destination file: %w", err) - } - defer SafeClose(destFile) - - if _, err := io.Copy(destFile, gzReader); err != nil { - return fmt.Errorf("unzip copy error: %w", err) - } - - fmt.Printf("Unzipped logs to %s\n", destPath) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") - } - - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) - } - - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) - } - -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go deleted file mode 100644 index fe61acf..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-dev-full-example.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go deleted file mode 100644 index e957167..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/main.snippet.get-metrics-prod-full-example.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go b/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go deleted file mode 100644 index 0e761b9..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/full-example/secrets_loader.snippet.secrets-loader-function-full-example.go +++ /dev/null @@ -1,35 +0,0 @@ - -package internal - -import ( - "fmt" - "github.com/joho/godotenv" - "log" - "os" -) - -type Secrets struct { - ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` - ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` -} - -// LoadSecrets loads environment variables from a .env file to use in the application -func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load("./.env"); err != nil { - log.Println("No .env file found") - } - secrets := &Secrets{ - ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), - ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), - } - return secrets, nil -} - -// CheckRequiredEnv verifies that required environment variables are set in .env -func (s *Secrets) CheckRequiredEnv() error { - if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { - return fmt.Errorf("service account client credentials must be set") - } - return nil -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go deleted file mode 100644 index cd40582..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs-main.go +++ /dev/null @@ -1,27 +0,0 @@ -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") - } - - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) - } - - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) - } - -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go deleted file mode 100644 index cfc25f4..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-logs.go +++ /dev/null @@ -1,111 +0,0 @@ -// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -package main - -import ( - "atlas-sdk-go/internal/auth" - "compress/gzip" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" - "strings" -) - -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - -// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for -// the specified host in your project. -func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { - logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) - fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - - if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { - return "", err - } - - fmt.Printf("Logs saved to %s\n", logFileName) - return logFileName, nil -} - -func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return fmt.Errorf("fetch logs: %w", err) - } - defer SafeClose(resp) - - file, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("create %q: %w", filePath, err) - } - defer SafeClose(file) - - if _, err := io.Copy(file, resp); err != nil { - return fmt.Errorf("write to %q: %w", filePath, err) - } - - return nil -} - -func unzipGzFile(srcPath, destPath string) error { - srcFile, err := os.Open(srcPath) - if err != nil { - return fmt.Errorf("open gz file: %w", err) - } - defer SafeClose(srcFile) - - gzReader, err := gzip.NewReader(srcFile) - if err != nil { - return fmt.Errorf("create gzip reader: %w", err) - } - defer SafeClose(gzReader) - - destFile, err := os.Create(destPath) - if err != nil { - return fmt.Errorf("create destination file: %w", err) - } - defer SafeClose(destFile) - - if _, err := io.Copy(destFile, gzReader); err != nil { - return fmt.Errorf("unzip copy error: %w", err) - } - - fmt.Printf("Unzipped logs to %s\n", destPath) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") - } - - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) - } - - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) - } - -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go deleted file mode 100644 index 95ce8ea..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-dev.go +++ /dev/null @@ -1,64 +0,0 @@ -// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go deleted file mode 100644 index 4cd22c5..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-dev.go +++ /dev/null @@ -1,31 +0,0 @@ -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go deleted file mode 100644 index f07839a..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-main-prod.go +++ /dev/null @@ -1,32 +0,0 @@ -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go b/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go deleted file mode 100644 index 99f27d0..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/main.snippet.get-metrics-prod.go +++ /dev/null @@ -1,67 +0,0 @@ -// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json b/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json deleted file mode 100644 index 65f9e17..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/usage-examples/snippet.config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "", - "ATLAS_PROJECT_ID": "", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" -} diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index 79c1e58..1b1c68d 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -1,26 +1,36 @@ [//]: # (.. Don't Copy to Target Repo ) # Atlas SDK for Go +This project demonstrates how to script specific functionality using the Atlas SDK for Go. Code examples are included in the Atlas Architecture Center docs and available in a user-facing version of the project. + +- Generated usage examples, which are included directly in the docs +- Within a + ## Project Structure ```text atlas-sdk-go/ +│── bluehawk/ # Bluehawk scripts to snip and copy code examples +│ ├── copy.sh +│ ├── snip.sh │── cmd/ # Self-contained, runnable scripts │ ├── get_logs/ │ ├── main.go -│ ├── get_metrics/ -│ ├── main.go +│ ├── get_metrics/ +│ ├── dev/ +│ ├── main.go +│ ├── prod/ +│ ├── main.go │── config/ # Atlas configuration settings │ ├── config.json │── internal/ # Shared internal logic │── auth/ ├── auth.go -│ ├── api_client.go │ ├── config_loader.go │ ├── secrets_loader.go │── .env # Secrets file (excluded from Git) │── go.mod │── go.sum -│── README.md +│── README.md # Internal-only README (do not copy) ``` ## Runnable Scripts @@ -33,14 +43,18 @@ For example, to run `get_logs/main.go`: ## Set up +### Prerequisites + +- A [service account](https://www.mongodb.com/docs/atlas/api/service-accounts-overview/#std-label-service-accounts-overview) with access to your Atlas project + ### Set environment variables and config file -1. Create a `.env` file in the root directory with the following environment variables: +1. Set the following variable values, either as a `.env` file in the root directory or through your IDE ```shell MONGODB_ATLAS_SERVICE_ACCOUNT_ID=your-service-account-id MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET=your-service-account-secret ``` -2. Update the placeholders in the `configs/config.json` file with your Atlas information: +2. Update the placeholders in the `configs/config.json` file with your Atlas cluster information: ```json { @@ -48,8 +62,6 @@ For example, to run `get_logs/main.go`: "ATLAS_ORG_ID": "", "ATLAS_PROJECT_ID": "", "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.ab1cd.mongodb.net", - "ATLAS_PORT": "27017", "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" } @@ -57,6 +69,28 @@ For example, to run `get_logs/main.go`: > **NOTE: Group ID == Project ID** Groups and projects are synonymous terms. Groups and projects are synonymous terms. Your group id is the same as your project id. 3. +## Generate Examples + +### Generate code usage examples for docs +This project uses the following Bluehawk commands to generate the code examples: + +- Usage examples for the docs. These are generated using the `bluehawk snip` command based on the `snippet` markup in the code file. + ```shell + ./bluehawk/snip.sh + ``` + +### Copy project files for user-facing project repo + +To copy the full project files for the user-facing artifact repo. These are generated using the `bluehawk copy` command, and any specified files are ignored. + ```shell + ./bluehawk/copy.sh + ``` + +> **NOTE: "Copy" State** This project uses a state named "copy" specifically for any manipulations needed for code copied to the artifact repo. + +## Copy Generated Examples to Other Repos + + --- scratchpad: diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh b/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh deleted file mode 100755 index 2821680..0000000 --- a/usage-examples/go/atlas-sdk-go/bluehawk/bluehawkProject.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# —— Paths —— -PROJECT=$(git rev-parse --show-toplevel) -SRC_ROOT="$PROJECT/usage-examples/go/atlas-sdk-go" -DST_ROOT="$PROJECT/generated-usage-examples/go/atlas-sdk-go/full-example" - -# —— Helper to run Bluehawk snip and prune nested snippets —— -run_snip() { - local src="$1" dst="$2" label="$3" - - echo "→ $label" - npx bluehawk snip "$src" -o "$dst" \ - - # Remove any snippet files that are NOT the “-full-example” ones - find "$dst" -type f \ - -name '*.snippet.*' \ - ! -name '*.snippet.*-full-example.*' \ - -delete -print \ - | sed 's/^/ └ removed: /' -} - -# —— 1) Snip these source paths into the same relative spot under DST_ROOT —— -SNIP_PATHS=( - "cmd/get_logs" - "cmd/get_metrics" - "internal" - "internal/auth" - "" # root of SRC_ROOT -) - -for rel in "${SNIP_PATHS[@]}"; do - src="$SRC_ROOT/$rel" - dst="$DST_ROOT/$rel" - mkdir -p "$dst" - label="Snip ${rel:-root}" - run_snip "$src" "$dst" "$label" -done - -# —— 2) Copy raw/static files into the same structure —— -## DON'T COPY SOURCE README.md TO TARGET REPO -STATIC_FILES=( - "configs/config.json" - "go.mod" - "go.sum" -) - -echo "→ Copying static files" -for rel in "${STATIC_FILES[@]}"; do - src="$SRC_ROOT/$rel" - dst_dir="$DST_ROOT/$(dirname "$rel")" - mkdir -p "$dst_dir" - cp "$src" "$dst_dir/" - echo " • $rel" -done - -# —— 3) Clean up any .gz logs in the whole project —— -find "$PROJECT" -name "*.gz" -type f -delete diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/copy.sh b/usage-examples/go/atlas-sdk-go/bluehawk/copy.sh new file mode 100644 index 0000000..551ca4d --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/bluehawk/copy.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Copy project files to generated directory using Bluehawk +# Copied files are then pushed to Arch Center artifact repo via Copier App +set -euo pipefail + +# Set input and output directories +PROJECT=$(git rev-parse --show-toplevel) +INPUT_DIR="$PROJECT/usage-examples/go/atlas-sdk-go/" +OUTPUT_DIR="$PROJECT/generated-usage-examples/go/atlas-sdk-go/project-copy/" + +# Set ignored internal files and directories +IGNORE=( + "README.md" + "bluehawk/" + "tests/" + ".env" + "*.gz" + "*.log" +) +IGNORE_ARGS=() +for path in "${IGNORE[@]}"; do + IGNORE_ARGS+=("--ignore=$path") +done + +# Run Bluehawk copy command, passing all ignore args and "copy" state +bluehawk copy \ + "${IGNORE_ARGS[@]}" \ + --state copy \ + -o "$OUTPUT_DIR" \ + "$INPUT_DIR" diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh b/usage-examples/go/atlas-sdk-go/bluehawk/snip.sh similarity index 100% rename from usage-examples/go/atlas-sdk-go/bluehawk/bluehawk.sh rename to usage-examples/go/atlas-sdk-go/bluehawk/snip.sh diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 565f516..292d149 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -1,6 +1,7 @@ // :snippet-start: get-logs +// :state-remove-start: copy // See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -// :snippet-start: get-logs-full-example +// :state-remove-end: [copy] package main import ( @@ -16,14 +17,6 @@ import ( "strings" ) -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - // getHostLogs downloads a compressed .gz file that contains the MongoDB logs for // the specified host in your project. func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { @@ -38,6 +31,14 @@ func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin return logFileName, nil } +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("Warning: failed to close resource: %v", err) + } + } +} + func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() if err != nil { @@ -97,8 +98,8 @@ func main() { params := &admin.GetHostLogsApiParams{ GroupId: config.ProjectID, - HostName: config.HostName, // The host to get logs for - LogName: "mongodb", // The type of log to get ("mongodb" or "mongos") + HostName: config.HostName, + LogName: "mongodb", // Type of log ("mongodb" or "mongos") } logFileName, err := getHostLogs(ctx, *client, params) @@ -120,5 +121,4 @@ func main() { } // :snippet-end: [get-logs-main] -// :snippet-end: [get-logs-full-example] // :snippet-end: [get-logs] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go index 1c3987b..9d4682f 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go @@ -1,6 +1,7 @@ // :snippet-start: get-metrics-dev +// :state-remove-start: copy // See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -// :snippet-start: get-metrics-dev-full-example +// :state-remove-end: [copy] package main import ( @@ -66,5 +67,4 @@ func main() { } // :snippet-end: [get-metrics-main-prod] -// :snippet-end: [get-metrics-prod-full-example] // :snippet-end: [get-metrics-prod] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go index 32e18bf..e475986 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go @@ -1,6 +1,7 @@ // :snippet-start: get-metrics-prod +// :state-remove-start: copy // See entire project at https://github.com/mongodb/atlas-architecture-go-sdk -// :snippet-start: get-metrics-prod-full-example +// :state-remove-end: [copy] package main import ( @@ -69,5 +70,4 @@ func main() { } // :snippet-end: [get-metrics-main-prod] -// :snippet-end: [get-metrics-prod-full-example] // :snippet-end: [get-metrics-prod] diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index e666c7b..2580744 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -1,4 +1,3 @@ -// :snippet-start: auth-function-full-example package auth import ( @@ -8,14 +7,7 @@ import ( "go.mongodb.org/atlas-sdk/v20250219001/admin" ) -// :replace-start: { -// "terms": { -// "zz-": "" -// } -// } -const filePath = "./configs/zz-config.json" - -// :replace-end: +const filePath = "./configs/config.json" // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. @@ -49,5 +41,3 @@ func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, return atlasClient, secrets, config, nil } - -// :snippet-end: [auth-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go index 8a60c9b..d75df81 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/config_loader.go @@ -1,4 +1,3 @@ -// :snippet-start: config-loader-function-full-example package internal import ( @@ -55,5 +54,3 @@ func (c *Config) CheckRequiredFields() error { } return nil } - -// :snippet-end: [config-loader-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go index 4402e25..a315f65 100644 --- a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go +++ b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go @@ -1,5 +1,3 @@ -// :snippet-start: secrets-loader-function-full-example - package internal import ( @@ -18,7 +16,7 @@ type Secrets struct { ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` } -// LoadSecrets loads environment variables from a .env file to use in the application +// LoadSecrets loads .env file variables to use in the application func LoadSecrets() (*Secrets, error) { if err := godotenv.Load("./.env"); err != nil { log.Println("No .env file found") @@ -34,12 +32,10 @@ func LoadSecrets() (*Secrets, error) { return secrets, nil } -// CheckRequiredEnv verifies that required environment variables are set in .env +// CheckRequiredEnv verifies that required environment variables are set func (s *Secrets) CheckRequiredEnv() error { if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { return fmt.Errorf("service account client credentials must be set") } return nil } - -// :snippet-end: [secrets-loader-function-full-example] diff --git a/usage-examples/go/atlas-sdk-go/run_cmd.sh b/usage-examples/go/atlas-sdk-go/tests/run_cmd.sh similarity index 100% rename from usage-examples/go/atlas-sdk-go/run_cmd.sh rename to usage-examples/go/atlas-sdk-go/tests/run_cmd.sh From 2c37b2c9ac78482c8d962f0f6f57f614acdc513e Mon Sep 17 00:00:00 2001 From: cbullinger Date: Tue, 29 Apr 2025 10:45:44 -0400 Subject: [PATCH 18/22] Clean up for copy to artifact repo --- .../cmd/{get_metrics/dev => get_metrics_disk}/main.go | 0 .../{get_metrics/prod => get_metrics_process}/main.go | 0 usage-examples/go/atlas-sdk-go/configs/.config.json | 9 +++++++++ usage-examples/go/atlas-sdk-go/internal/auth/auth.go | 2 +- .../go/atlas-sdk-go/tests/{cleanup.go => utils.go} | 0 5 files changed, 10 insertions(+), 1 deletion(-) rename usage-examples/go/atlas-sdk-go/cmd/{get_metrics/dev => get_metrics_disk}/main.go (100%) rename usage-examples/go/atlas-sdk-go/cmd/{get_metrics/prod => get_metrics_process}/main.go (100%) create mode 100644 usage-examples/go/atlas-sdk-go/configs/.config.json rename usage-examples/go/atlas-sdk-go/tests/{cleanup.go => utils.go} (100%) diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go similarity index 100% rename from usage-examples/go/atlas-sdk-go/cmd/get_metrics/dev/main.go rename to usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go similarity index 100% rename from usage-examples/go/atlas-sdk-go/cmd/get_metrics/prod/main.go rename to usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go diff --git a/usage-examples/go/atlas-sdk-go/configs/.config.json b/usage-examples/go/atlas-sdk-go/configs/.config.json new file mode 100644 index 0000000..46c9a4d --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/configs/.config.json @@ -0,0 +1,9 @@ +{ + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "5bfda007553855125605a5cf", + "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", + "ATLAS_PORT": "27017", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" +} diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go index 2580744..3bd7d5c 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go @@ -7,7 +7,7 @@ import ( "go.mongodb.org/atlas-sdk/v20250219001/admin" ) -const filePath = "./configs/config.json" +const filePath = "./configs/.config.json" // CreateAtlasClient initializes and returns an authenticated Atlas API client // using OAuth2 with service account credentials. diff --git a/usage-examples/go/atlas-sdk-go/tests/cleanup.go b/usage-examples/go/atlas-sdk-go/tests/utils.go similarity index 100% rename from usage-examples/go/atlas-sdk-go/tests/cleanup.go rename to usage-examples/go/atlas-sdk-go/tests/utils.go From de004d88087bc12eab401ccd66d544aa4706af63 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Mon, 5 May 2025 12:46:52 -0400 Subject: [PATCH 19/22] Refactor and write unit tests --- .github/workflows/test-go-sdk.yml | 14 ++ .../{bluehawk => .bluehawk}/copy.sh | 16 +- .../{bluehawk => .bluehawk}/snip.sh | 8 +- usage-examples/go/atlas-sdk-go/README.md | 96 ++++------ usage-examples/go/atlas-sdk-go/REPO_README.md | 51 +++++ .../go/atlas-sdk-go/cmd/get_logs/main.go | 124 ++++--------- .../atlas-sdk-go/cmd/get_metrics_disk/main.go | 66 +++---- .../cmd/get_metrics_process/main.go | 70 +++---- .../go/atlas-sdk-go/configs/.config.json | 2 - usage-examples/go/atlas-sdk-go/go.mod | 1 + usage-examples/go/atlas-sdk-go/go.sum | 2 + .../go/atlas-sdk-go/internal/auth/auth.go | 43 ----- .../go/atlas-sdk-go/internal/auth/client.go | 25 +++ .../go/atlas-sdk-go/internal/config/json.go | 49 +++++ .../go/atlas-sdk-go/internal/config/loader.go | 20 ++ .../atlas-sdk-go/internal/config/secrets.go | 50 +++++ .../go/atlas-sdk-go/internal/config_loader.go | 56 ------ .../go/atlas-sdk-go/internal/logs/fetch.go | 26 +++ .../atlas-sdk-go/internal/logs/fetch_test.go | 83 +++++++++ .../go/atlas-sdk-go/internal/logs/file.go | 23 +++ .../atlas-sdk-go/internal/logs/file_test.go | 33 ++++ .../go/atlas-sdk-go/internal/logs/gzip.go | 34 ++++ .../atlas-sdk-go/internal/logs/gzip_test.go | 50 +++++ .../go/atlas-sdk-go/internal/metrics/disk.go | 32 ++++ .../internal/metrics/disk_test.go | 77 ++++++++ .../atlas-sdk-go/internal/metrics/process.go | 31 ++++ .../internal/metrics/process_test.go | 91 +++++++++ .../atlas-sdk-go/internal/secrets_loader.go | 41 ----- .../go/atlas-sdk-go/internal/utils.go | 49 +++++ .../go/atlas-sdk-go/scripts/bluehawk.sh | 70 +++++++ .../go/atlas-sdk-go/tests/mock_test.go | 174 ------------------ usage-examples/go/atlas-sdk-go/tests/mocks.go | 44 ----- .../go/atlas-sdk-go/tests/run_cmd.sh | 19 -- usage-examples/go/atlas-sdk-go/tests/utils.go | 42 ----- 34 files changed, 945 insertions(+), 667 deletions(-) create mode 100644 .github/workflows/test-go-sdk.yml rename usage-examples/go/atlas-sdk-go/{bluehawk => .bluehawk}/copy.sh (65%) rename usage-examples/go/atlas-sdk-go/{bluehawk => .bluehawk}/snip.sh (84%) create mode 100644 usage-examples/go/atlas-sdk-go/REPO_README.md delete mode 100644 usage-examples/go/atlas-sdk-go/internal/auth/auth.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/auth/client.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/config/json.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/config/loader.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/config/secrets.go delete mode 100644 usage-examples/go/atlas-sdk-go/internal/config_loader.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/fetch.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/file.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/file_test.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/gzip.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/logs/gzip_test.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/metrics/disk.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/metrics/process.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go delete mode 100644 usage-examples/go/atlas-sdk-go/internal/secrets_loader.go create mode 100644 usage-examples/go/atlas-sdk-go/internal/utils.go create mode 100755 usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh delete mode 100644 usage-examples/go/atlas-sdk-go/tests/mock_test.go delete mode 100644 usage-examples/go/atlas-sdk-go/tests/mocks.go delete mode 100755 usage-examples/go/atlas-sdk-go/tests/run_cmd.sh delete mode 100644 usage-examples/go/atlas-sdk-go/tests/utils.go diff --git a/.github/workflows/test-go-sdk.yml b/.github/workflows/test-go-sdk.yml new file mode 100644 index 0000000..bd0b13d --- /dev/null +++ b/.github/workflows/test-go-sdk.yml @@ -0,0 +1,14 @@ +# name: CI +# on: [push, pull_request] +# jobs: +# test: +# runs-on: ubuntu-latest +# steps: +# - name: Checkout code +# uses: actions/checkout@v4 +# - name: Set up Go +# uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# - name: Test +# run: go test \ No newline at end of file diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/copy.sh b/usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh similarity index 65% rename from usage-examples/go/atlas-sdk-go/bluehawk/copy.sh rename to usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh index 551ca4d..9bfc0e2 100644 --- a/usage-examples/go/atlas-sdk-go/bluehawk/copy.sh +++ b/usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh @@ -9,12 +9,12 @@ PROJECT=$(git rev-parse --show-toplevel) INPUT_DIR="$PROJECT/usage-examples/go/atlas-sdk-go/" OUTPUT_DIR="$PROJECT/generated-usage-examples/go/atlas-sdk-go/project-copy/" -# Set ignored internal files and directories +# Set directories and files to ignore IGNORE=( "README.md" "bluehawk/" "tests/" - ".env" + ".*" "*.gz" "*.log" ) @@ -23,8 +23,18 @@ for path in "${IGNORE[@]}"; do IGNORE_ARGS+=("--ignore=$path") done +# Set directories and files to rename +RENAME=( + "REPO_README.md:README.md" +) +RENAME_ARGS=() +for path in "${RENAME[@]}"; do + IFS=":" read -r src dst <<< "$path" # Split the path into source and destination + RENAME_ARGS+=("--rename=$src:$dst") # Add the rename argument to the array +done + # Run Bluehawk copy command, passing all ignore args and "copy" state -bluehawk copy \ +.bluehawk copy \ "${IGNORE_ARGS[@]}" \ --state copy \ -o "$OUTPUT_DIR" \ diff --git a/usage-examples/go/atlas-sdk-go/bluehawk/snip.sh b/usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh similarity index 84% rename from usage-examples/go/atlas-sdk-go/bluehawk/snip.sh rename to usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh index 6966e31..e180edc 100755 --- a/usage-examples/go/atlas-sdk-go/bluehawk/snip.sh +++ b/usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh @@ -5,11 +5,11 @@ PROJECT=$(git rev-parse --show-toplevel) GO_SDK_EXAMPLES="$PROJECT/usage-examples/go/atlas-sdk-go/" GENERATED_EXAMPLES="$PROJECT/generated-usage-examples/go/atlas-sdk-go/usage-examples/" -# ——— helper: run bluehawk and only show the key lines ——— +# ——— helper: run .bluehawk and only show the key lines ——— run_snip() { local extra_flags="$1" local label="$2" - local dst="$GENERATED_EXAMPLES" + local dest="$GENERATED_EXAMPLES" echo "→ $label" npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" @@ -18,9 +18,9 @@ run_snip() { run_snip "" "Global snippets" # ——— 2) state‑specific snippets ——— -read -p "Do you have any state tags to enter? [y/N]: " resp +read -r -p "Do you have any state tags to enter? [y/N]: " resp if [[ $resp =~ ^[Yy]$ ]]; then - read -a STATES -p "Enter one or more state tags (space‑separated): " + read -r -a STATES -p "Enter one or more state tags (space‑separated): " for s in "${STATES[@]}"; do run_snip "--state $s" "State: $s" done diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index 1b1c68d..be9cd5d 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -1,44 +1,40 @@ -[//]: # (.. Don't Copy to Target Repo ) # Atlas SDK for Go -This project demonstrates how to script specific functionality using the Atlas SDK for Go. Code examples are included in the Atlas Architecture Center docs and available in a user-facing version of the project. - -- Generated usage examples, which are included directly in the docs -- Within a +This project demonstrates how to script specific functionality using the Atlas +SDK for Go. Code examples are used in the Atlas Architecture Center docs, and +the project is made available in a user-facing repo. ## Project Structure ```text atlas-sdk-go/ -│── bluehawk/ # Bluehawk scripts to snip and copy code examples -│ ├── copy.sh -│ ├── snip.sh │── cmd/ # Self-contained, runnable scripts │ ├── get_logs/ │ ├── main.go -│ ├── get_metrics/ -│ ├── dev/ -│ ├── main.go -│ ├── prod/ -│ ├── main.go +│ ├── get_metrics_disk/ +│ ├── main.go +│ ├── get_metrics_process/ +│ ├── main.go │── config/ # Atlas configuration settings │ ├── config.json │── internal/ # Shared internal logic - │── auth/ - ├── auth.go -│ ├── config_loader.go -│ ├── secrets_loader.go +│ ├── auth/ +| ├── client.go +│ ├── config/ +| ├── json.go +| ├── secrets.go +| ├── loader.go │── .env # Secrets file (excluded from Git) │── go.mod │── go.sum -│── README.md # Internal-only README (do not copy) +│── README.md # Internal-only README (do not copy with Copier Tool) +│── scripts/ # Internal-only Bluehawk scripts to snip and copy code examples +│ ├── bluehawk.sh ``` ## Runnable Scripts -You can run individual scripts using `run_cmd.sh` and specifying the script's action (i.e. the parent directory for the `main.go` you want to run). - -For example, to run `get_logs/main.go`: +You can run individual scripts from the terminal. For example, to run `get_logs/main.go`: ```shell -./run_cmd.sh get_logs +go run cmd/get_logs/main.go ``` ## Set up @@ -47,9 +43,11 @@ For example, to run `get_logs/main.go`: - A [service account](https://www.mongodb.com/docs/atlas/api/service-accounts-overview/#std-label-service-accounts-overview) with access to your Atlas project +> **NOTE:** Some scripts require an M10+ cluster + ### Set environment variables and config file -1. Set the following variable values, either as a `.env` file in the root directory or through your IDE +1. Set the following variable values, either as a `.env` file in the root directory or through your IDE: ```shell MONGODB_ATLAS_SERVICE_ACCOUNT_ID=your-service-account-id MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET=your-service-account-secret @@ -67,54 +65,26 @@ For example, to run `get_logs/main.go`: } ``` > **NOTE: Group ID == Project ID** Groups and projects are synonymous terms. Groups and projects are synonymous terms. Your group id is the same as your project id. -3. + +## Write Tests + +# TODO ## Generate Examples -### Generate code usage examples for docs -This project uses the following Bluehawk commands to generate the code examples: +This project uses Bluehawk to generate code examples from the source code. -- Usage examples for the docs. These are generated using the `bluehawk snip` command based on the `snippet` markup in the code file. - ```shell - ./bluehawk/snip.sh - ``` +- Usage examples for the docs. These are generated using the `bluehawk snip` + command based on the `snippet` markup in the code file. +- Full project files for the user-facing project repo. These are generated using + the `bluehawk copy` command. -### Copy project files for user-facing project repo +Run the bluehawk script and enter either `snip` or `copy`. The selected command +runs with the defined defaults. -To copy the full project files for the user-facing artifact repo. These are generated using the `bluehawk copy` command, and any specified files are ignored. ```shell - ./bluehawk/copy.sh + ./scripts/bluehawk.sh ``` > **NOTE: "Copy" State** This project uses a state named "copy" specifically for any manipulations needed for code copied to the artifact repo. -## Copy Generated Examples to Other Repos - - - ---- -scratchpad: -- manually test against real infra -- pull the real data - -PR Push > run on captured data -& scheduled job to validate? (or bump our sdk version along with the v release & -verify; fix any failing test) -- run the gh action locally ---- -1. go sdk testing -2. atlas testing - -we'd need to be notified when either change -we can test sdk automatically with the captured data - -periodic manual validation step to test the infra side -- release cadence for sdk > gh -- release cadence for atlas/infra > server version? api update? ---- -arch center docs versioning considerations -- how to keep arch center version in sync with code example version updates? ---- -snippets in generated-examples > push to arch center repo to use in docs? ---- -narrating out loud the next step? diff --git a/usage-examples/go/atlas-sdk-go/REPO_README.md b/usage-examples/go/atlas-sdk-go/REPO_README.md new file mode 100644 index 0000000..e761866 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/REPO_README.md @@ -0,0 +1,51 @@ +# MongoDB Atlas Architecture Center Go SDK Code Examples + +This repository contains [Atlas Go SDK](https://www.mongodb.com/docs/atlas/sdk/) +code examples that follow recommendations in MongoDB's official +[Atlas Architecture Center documentation](https://www.mongodb.com/docs/atlas/architecture/current/). +You can run, download, and modify these code examples as starting points for +configuring your MongoDB Atlas architecture for your use case. + +## Overview + +### Project Structure + +```text +Project Root +├── cmd +│ ├── get_logs/main.go +│ ├── get_metrics_disk/main.go +│ ├── get_metrics_process/main.go +├── internal +│ ├── auth +│ │ ├── auth.go +│ ├── logs +│ │ ├── downloader.go +│ ├── metrics +│ │ ├── metrics.go +├── go.mod +├── go.sum +├── configs +│ ├── config.json +├── .env # +``` + +> NOTE: In a production environment, you are likely to use + +note in the README that you'll most likely be using a secrets manager in prod +## License + +This project is licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). + +## Issues + +To report an issue with any of these code examples, please leave feedback +through the corresponding documentation page in the +[MongoDB Atlas Architecture Center](https://www.mongodb.com/docs/atlas/architecture/current/). +Using the `Rate This Page` button, you can add a comment about the issue after +leaving a star rating. + +## Contributing + +We are not currently accepting public contributions to this repository at this +time.**** diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 292d149..78c5a7d 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -5,120 +5,66 @@ package main import ( + "atlas-sdk-go/internal" "atlas-sdk-go/internal/auth" - test "atlas-sdk-go/tests" // :remove: - "compress/gzip" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" "context" "fmt" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" "log" "os" - "strings" + "path/filepath" + "time" ) -// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for -// the specified host in your project. -func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { - logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) - fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - - if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { - return "", err - } - - fmt.Printf("Logs saved to %s\n", logFileName) - return logFileName, nil -} - -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - -func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return fmt.Errorf("fetch logs: %w", err) - } - defer SafeClose(resp) - - file, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("create %q: %w", filePath, err) - } - defer SafeClose(file) - - if _, err := io.Copy(file, resp); err != nil { - return fmt.Errorf("write to %q: %w", filePath, err) - } - - return nil -} - -func unzipGzFile(srcPath, destPath string) error { - srcFile, err := os.Open(srcPath) - if err != nil { - return fmt.Errorf("open gz file: %w", err) - } - defer SafeClose(srcFile) - - gzReader, err := gzip.NewReader(srcFile) +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/.config.json") if err != nil { - return fmt.Errorf("create gzip reader: %w", err) + log.Fatalf("config load: %v", err) } - defer SafeClose(gzReader) - destFile, err := os.Create(destPath) + sdk, err := auth.NewClient(cfg, secrets) if err != nil { - return fmt.Errorf("create destination file: %w", err) - } - defer SafeClose(destFile) - - if _, err := io.Copy(destFile, gzReader); err != nil { - return fmt.Errorf("unzip copy error: %w", err) + log.Fatalf("client init: %v", err) } - fmt.Printf("Unzipped logs to %s\n", destPath) - return nil -} - -// :snippet-start: get-logs-main -func main() { ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) + p := &admin.GetHostLogsApiParams{ + GroupId: cfg.ProjectID, + HostName: cfg.HostName, + LogName: "mongodb", } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, - LogName: "mongodb", // Type of log ("mongodb" or "mongos") + ts := time.Now().Format("20060102_150405") + base := fmt.Sprintf("%s_%s_%s", p.HostName, p.LogName, ts) + outDir := "logs" + os.MkdirAll(outDir, 0o755) + gzPath := filepath.Join(outDir, base+".gz") + txtPath := filepath.Join(outDir, base+".txt") + + rc, err := logs.FetchHostLogs(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("download logs: %v", err) } + defer internal.SafeClose(rc) - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) + if err := logs.WriteToFile(rc, gzPath); err != nil { + log.Fatalf("save gz: %v", err) } + fmt.Println("Saved compressed log to", gzPath) - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) + if err := logs.DecompressGzip(gzPath, txtPath); err != nil { + log.Fatalf("decompress: %v", err) } + fmt.Println("Uncompressed log to", txtPath) // :remove-start: // NOTE Internal function to clean up any downloaded files - if err := test.CleanupFiles(); err != nil { + if err := internal.SafeDelete(outDir); err != nil { log.Printf("Cleanup error: %v", err) } + fmt.Println("Deleted generated files from", outDir) // :remove-end: } - -// :snippet-end: [get-logs-main] -// :snippet-end: [get-logs] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go index 9d4682f..766ec9c 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go @@ -6,65 +6,45 @@ package main import ( "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" ) -// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/.config.json") if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) + log.Fatalf("config load: %v", err) } - fmt.Println(string(jsonData)) - return resp, nil -} -// :snippet-start: get-metrics-main-dev -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() + sdk, err := auth.NewClient(cfg, secrets) if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) + log.Fatalf("client init: %v", err) } - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", + ctx := context.Background() + p := &admin.GetDiskMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + PartitionName: "data", + M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, + Granularity: admin.PtrString("P1D"), + Period: admin.PtrString("P1D"), } - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) + view, err := metrics.FetchDiskMetrics(ctx, sdk.MonitoringAndLogsApi, p) if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) + log.Fatalf("disk metrics: %v", err) } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) } -// :snippet-end: [get-metrics-main-prod] -// :snippet-end: [get-metrics-prod] +// :snippet-end: [get-metrics-dev] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go index e475986..fa2ac29 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go @@ -6,68 +6,50 @@ package main import ( "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" ) -// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/.config.json") if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) + log.Fatalf("config load: %v", err) } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") + sdk, err := auth.NewClient(cfg, secrets) if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) + log.Fatalf("client init: %v", err) } - fmt.Println(string(jsonData)) - return resp, nil -} -// :snippet-start: get-metrics-main-prod -func main() { ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) + p := &admin.GetHostMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + M: &[]string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + }, + Granularity: admin.PtrString("PT1H"), + Period: admin.PtrString("P7D"), } - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) + view, err := metrics.FetchProcessMetrics(ctx, sdk.MonitoringAndLogsApi, p) if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) + log.Fatalf("process metrics: %v", err) } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) } -// :snippet-end: [get-metrics-main-prod] // :snippet-end: [get-metrics-prod] diff --git a/usage-examples/go/atlas-sdk-go/configs/.config.json b/usage-examples/go/atlas-sdk-go/configs/.config.json index 46c9a4d..e426705 100644 --- a/usage-examples/go/atlas-sdk-go/configs/.config.json +++ b/usage-examples/go/atlas-sdk-go/configs/.config.json @@ -3,7 +3,5 @@ "ATLAS_ORG_ID": "5bfda007553855125605a5cf", "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_HOST_NAME": "cluster0-shard-00-00.nr3ko.mongodb.net", - "ATLAS_PORT": "27017", "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" } diff --git a/usage-examples/go/atlas-sdk-go/go.mod b/usage-examples/go/atlas-sdk-go/go.mod index 1a74333..f26b6af 100644 --- a/usage-examples/go/atlas-sdk-go/go.mod +++ b/usage-examples/go/atlas-sdk-go/go.mod @@ -12,6 +12,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/mongodb-forks/digest v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect golang.org/x/oauth2 v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/usage-examples/go/atlas-sdk-go/go.sum b/usage-examples/go/atlas-sdk-go/go.sum index f7ec5e3..01a0f83 100644 --- a/usage-examples/go/atlas-sdk-go/go.sum +++ b/usage-examples/go/atlas-sdk-go/go.sum @@ -8,6 +8,8 @@ github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKk github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go b/usage-examples/go/atlas-sdk-go/internal/auth/auth.go deleted file mode 100644 index 3bd7d5c..0000000 --- a/usage-examples/go/atlas-sdk-go/internal/auth/auth.go +++ /dev/null @@ -1,43 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const filePath = "./configs/.config.json" - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - - var secrets, err = internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - ctx := context.Background() - atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.BaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - return atlasClient, secrets, config, nil -} diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/client.go b/usage-examples/go/atlas-sdk-go/internal/auth/client.go new file mode 100644 index 0000000..eb28c0d --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/auth/client.go @@ -0,0 +1,25 @@ +package auth + +import ( + "atlas-sdk-go/internal/config" + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// NewClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials (recommended) +func NewClient(cfg *config.Config, secrets *config.Secrets) (*admin.APIClient, error) { + sdk, err := admin.NewClient( + admin.UseBaseURL(cfg.BaseURL), + admin.UseOAuthAuth(context.Background(), + secrets.ServiceAccountID, + secrets.ServiceAccountSecret, + ), + ) + if err != nil { + return nil, fmt.Errorf("create atlas client: %w", err) + } + return sdk, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/config/json.go b/usage-examples/go/atlas-sdk-go/internal/config/json.go new file mode 100644 index 0000000..d89bffd --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/config/json.go @@ -0,0 +1,49 @@ +package config + +import ( + "atlas-sdk-go/internal" + "encoding/json" + "fmt" + "os" + "strings" +) + +type Config struct { + BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` + OrgID string `json:"ATLAS_ORG_ID"` + ProjectID string `json:"ATLAS_PROJECT_ID"` + ClusterName string `json:"ATLAS_CLUSTER_NAME"` + HostName string + ProcessID string `json:"ATLAS_PROCESS_ID"` +} + +func LoadConfig(path string) (*Config, error) { + f, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("open config %s: %w", path, err) + } + defer internal.SafeClose(f) + + var c Config + if err := json.NewDecoder(f).Decode(&c); err != nil { + return nil, fmt.Errorf("decode %s: %w", path, err) + } + + // defaults + if c.BaseURL == "" { + c.BaseURL = "https://cloud.mongodb.com" + } + if c.HostName == "" { + // Go 1.18+: + if host, _, ok := strings.Cut(c.ProcessID, ":"); ok { + c.HostName = host + } + } + + // required + if c.OrgID == "" || c.ProjectID == "" { + return nil, fmt.Errorf("ATLAS_ORG_ID and ATLAS_PROJECT_ID are required") + } + + return &c, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/config/loader.go b/usage-examples/go/atlas-sdk-go/internal/config/loader.go new file mode 100644 index 0000000..6cad472 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/config/loader.go @@ -0,0 +1,20 @@ +package config + +import ( + "fmt" +) + +// LoadAll loads secrets and config from the specified paths +func LoadAll(configPath string) (*Secrets, *Config, error) { + s, err := LoadSecrets() + if err != nil { + return nil, nil, fmt.Errorf("loading secrets: %w", err) + } + + c, err := LoadConfig(configPath) + if err != nil { + return nil, nil, fmt.Errorf("loading config: %w", err) + } + + return s, c, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/config/secrets.go b/usage-examples/go/atlas-sdk-go/internal/config/secrets.go new file mode 100644 index 0000000..1698dcf --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/config/secrets.go @@ -0,0 +1,50 @@ +package config + +import ( + "fmt" + "os" + "strings" +) + +const ( + EnvMongoUser = "MONGODB_USER_NAME" + EnvMongoPassword = "MONGODB_PASSWORD" + EnvAtlasAPIKey = "MONGODB_ATLAS_PUBLIC_KEY" + EnvAtlasAPISecret = "MONGODB_ATLAS_PRIVATE_KEY" + EnvSAClientID = "MONGODB_ATLAS_SERVICE_ACCOUNT_ID" + EnvSAClientSecret = "MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET" +) + +type Secrets struct { + MongoDBUser string + MongoDBPassword string + AtlasAPIKey string + AtlasAPISecret string + ServiceAccountID string + ServiceAccountSecret string +} + +func LoadSecrets() (*Secrets, error) { + s := &Secrets{} + var missing []string + + look := func(key string, dest *string) { + if v, ok := os.LookupEnv(key); ok && v != "" { + *dest = v + } else { + missing = append(missing, key) + } + } + + look(EnvMongoUser, &s.MongoDBUser) + look(EnvMongoPassword, &s.MongoDBPassword) + look(EnvAtlasAPIKey, &s.AtlasAPIKey) + look(EnvAtlasAPISecret, &s.AtlasAPISecret) + look(EnvSAClientID, &s.ServiceAccountID) + look(EnvSAClientSecret, &s.ServiceAccountSecret) + + if len(missing) > 0 { + return nil, fmt.Errorf("missing required env vars: %s", strings.Join(missing, ", ")) + } + return s, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/config_loader.go b/usage-examples/go/atlas-sdk-go/internal/config_loader.go deleted file mode 100644 index d75df81..0000000 --- a/usage-examples/go/atlas-sdk-go/internal/config_loader.go +++ /dev/null @@ -1,56 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "os" - "strings" -) - -type Config struct { - BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` - OrgID string `json:"ATLAS_ORG_ID"` - ProjectID string `json:"ATLAS_PROJECT_ID"` - ClusterName string `json:"ATLAS_CLUSTER_NAME"` - HostName string - ProcessID string `json:"ATLAS_PROCESS_ID"` -} - -// LoadConfig loads a JSON config file to make it globally available -func LoadConfig(filePath string) (*Config, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Println("Error closing file") - } - }(file) - - var config Config - decoder := json.NewDecoder(file) - if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) - } - return &config, nil -} - -// SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if c.BaseURL == "" { - c.BaseURL = "https://cloud.mongodb.com" - } - if c.HostName == "" { - c.HostName = strings.Split(c.ProcessID, ":")[0] - } -} - -// CheckRequiredFields verifies that required Atlas fields are set in the config file -func (c *Config) CheckRequiredFields() error { - if c.OrgID == "" || c.ProjectID == "" { - return fmt.Errorf("missing required Atlas fields in config file") - } - return nil -} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/fetch.go b/usage-examples/go/atlas-sdk-go/internal/logs/fetch.go new file mode 100644 index 0000000..48ca8bc --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/fetch.go @@ -0,0 +1,26 @@ +package logs + +import ( + "context" + "fmt" + "io" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchHostLogs calls the Atlas SDK and returns the raw, compressed log stream. +func FetchHostLogs( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetHostLogsApiParams, +) (io.ReadCloser, error) { + req := sdk.GetHostLogs(ctx, p.GroupId, p.HostName, p.LogName) + rc, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to fetch logs: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("failed to fetch logs: %w", err) + } + return rc, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go b/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go new file mode 100644 index 0000000..b1c93b7 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go @@ -0,0 +1,83 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" +) + +func TestFetchHostLogs_Unit(t *testing.T) { + t.Parallel() + ctx := context.Background() + + // common params + params := &admin.GetHostLogsApiParams{ + GroupId: "gID", + HostName: "hName", + LogName: "mongodb", + } + + cases := []struct { + name string + setup func(m *mockadmin.MonitoringAndLogsApi) + wantErr bool + wantBody string + }{ + { + name: "API error", + wantErr: true, + setup: func(m *mockadmin.MonitoringAndLogsApi) { + m.EXPECT(). + GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). + Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() + m.EXPECT(). + GetHostLogsExecute(mock.Anything). + Return(nil, nil, fmt.Errorf("API error")).Once() + }, + }, + { + name: "Successful response", + wantErr: false, + wantBody: "log-data", + setup: func(m *mockadmin.MonitoringAndLogsApi) { + m.EXPECT(). + GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). + Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() + m.EXPECT(). + GetHostLogsExecute(mock.Anything). + Return(io.NopCloser(strings.NewReader("log-data")), nil, nil).Once() + }, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + tc.setup(mockSvc) + + rc, err := FetchHostLogs(ctx, mockSvc, params) + if tc.wantErr { + require.ErrorContainsf(t, err, "failed to fetch logs", "expected API error") + require.Nil(t, rc) + return + } + + require.NoError(t, err) + defer internal.SafeClose(rc) + + data, err := io.ReadAll(rc) + require.NoError(t, err) + require.Equal(t, tc.wantBody, string(data)) + }) + } +} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/file.go b/usage-examples/go/atlas-sdk-go/internal/logs/file.go new file mode 100644 index 0000000..dfed136 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/file.go @@ -0,0 +1,23 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "fmt" + "io" + "os" +) + +// WriteToFile copies everything from r into a new file at path. +// It will create (or truncate) that file. +func WriteToFile(r io.Reader, path string) error { + f, err := os.Create(path) + if err != nil { + return fmt.Errorf("create %s: %w", path, err) + } + defer internal.SafeClose(f) + + if err := internal.SafeCopy(f, r); err != nil { + return fmt.Errorf("write %s: %w", path, err) + } + return nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/file_test.go b/usage-examples/go/atlas-sdk-go/internal/logs/file_test.go new file mode 100644 index 0000000..8876d5a --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/file_test.go @@ -0,0 +1,33 @@ +package logs + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWriteToFile_Success(t *testing.T) { + // create a temp dir and file + tmp := t.TempDir() + path := filepath.Join(tmp, "out.txt") + + input := "hello world" + r := strings.NewReader(input) + + require.NoError(t, WriteToFile(r, path)) + + // verify file exists and content matches + data, err := os.ReadFile(path) + require.NoError(t, err) + require.Equal(t, input, string(data)) +} + +func TestWriteToFile_Error(t *testing.T) { + path := "does-not-exist/out.txt" + err := WriteToFile(strings.NewReader("x"), path) + require.Error(t, err) + require.Contains(t, err.Error(), "create") +} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go b/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go new file mode 100644 index 0000000..8505f93 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go @@ -0,0 +1,34 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "compress/gzip" + "fmt" + "os" +) + +// DecompressGzip opens a .gz file and unpacks to specified destination. +func DecompressGzip(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open %s: %w", srcPath, err) + } + defer internal.SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("gzip reader %s: %w", srcPath, err) + } + defer internal.SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create %s: %w", destPath, err) + } + defer internal.SafeClose(destFile) + + if err := internal.SafeCopy(destFile, gzReader); err != nil { + return fmt.Errorf("decompress to %s: %w", destPath, err) + } + return nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/gzip_test.go b/usage-examples/go/atlas-sdk-go/internal/logs/gzip_test.go new file mode 100644 index 0000000..9cbee64 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/logs/gzip_test.go @@ -0,0 +1,50 @@ +package logs + +import ( + "compress/gzip" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecompressGzip_Success(t *testing.T) { + // create a temp dir and file + tmp := t.TempDir() + src := filepath.Join(tmp, "test.gz") + dst := filepath.Join(tmp, "test.txt") + + // create a gzip file and write some data to it + f, err := os.Create(src) + require.NoError(t, err) + + gz := gzip.NewWriter(f) + _, err = gz.Write([]byte("foobar")) + require.NoError(t, err) + require.NoError(t, gz.Close()) + require.NoError(t, f.Close()) + + // call the function to test + require.NoError(t, DecompressGzip(src, dst)) + + // verify the output + data, err := os.ReadFile(dst) + require.NoError(t, err) + require.Equal(t, "foobar", string(data)) +} + +func TestDecompressGzip_SourceNotFound(t *testing.T) { + tmp := t.TempDir() + src := filepath.Join(tmp, "nofile.gz") + dst := filepath.Join(tmp, "out.txt") + + // source file does not exist + err := DecompressGzip(src, dst) + require.Error(t, err) + require.Contains(t, err.Error(), "open") + + // destination file does not exist + _, err2 := os.Stat(dst) + require.True(t, os.IsNotExist(err2)) +} diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go b/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go new file mode 100644 index 0000000..cd9d597 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go @@ -0,0 +1,32 @@ +package metrics + +import ( + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchDiskMetrics returns measurements for a specified disk partition +func FetchDiskMetrics( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetDiskMeasurementsApiParams, +) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + req := sdk.GetDiskMeasurements(ctx, p.GroupId, p.PartitionName, p.ProcessId) + req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) + + r, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("fetch disk metrics: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("fetch disk metrics: %w", err) + } + if r == nil || !r.HasMeasurements() { + return nil, fmt.Errorf("no metrics for partition %q on process %q", + p.PartitionName, p.ProcessId) + } + return r, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go b/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go new file mode 100644 index 0000000..66d425f --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go @@ -0,0 +1,77 @@ +package metrics + +import ( + "context" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" + "testing" +) + +// ----------------------------------------------------------------------------- +// Integration tests against test HTTP server +// ----------------------------------------------------------------------------- +// TODO: Implement integration tests + +// ----------------------------------------------------------------------------- +// Unit‐level tests against SDK mocks +// ----------------------------------------------------------------------------- + +func TestFetchDiskMetrics(t *testing.T) { + t.Parallel() + ctx := context.Background() + + cases := []struct { + name string + view *admin.ApiMeasurementsGeneralViewAtlas + wantErr bool + wantCount int + }{ + {name: "Happy path returns data", + view: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{{ + Name: admin.PtrString("DISK_METRIC"), + DataPoints: &[]admin.MetricDataPointAtlas{{ + Timestamp: admin.PtrTime(parseTS(t, fixedTS)), + Value: admin.PtrFloat32(4.56)}}}}}, + wantCount: 1}, + {name: "No available data returns error", + view: &admin.ApiMeasurementsGeneralViewAtlas{}, + wantErr: true}, + } + + baseDisk := admin.GetDiskMeasurementsApiParams{ + GroupId: "gID", + PartitionName: "part", + ProcessId: "pID", + Granularity: admin.PtrString("P1D"), + Period: admin.PtrString("P1D"), + M: &[]string{"DISK_METRIC"}, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + // setup mock SDK + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + mockSvc.EXPECT(). + GetDiskMeasurements(mock.Anything, baseDisk.GroupId, baseDisk.PartitionName, baseDisk.ProcessId). + Return(admin.GetDiskMeasurementsApiRequest{ApiService: mockSvc}).Once() + mockSvc.EXPECT(). + GetDiskMeasurementsExecute(mock.Anything). + Return(tc.view, nil, nil).Once() + + result, err := FetchDiskMetrics(ctx, mockSvc, &baseDisk) + + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) + require.Len(t, *result.Measurements, tc.wantCount) + }) + } +} diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/process.go b/usage-examples/go/atlas-sdk-go/internal/metrics/process.go new file mode 100644 index 0000000..53819b7 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/process.go @@ -0,0 +1,31 @@ +package metrics + +import ( + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchProcessMetrics returns measurements for a specified host process +func FetchProcessMetrics( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetHostMeasurementsApiParams, +) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + req := sdk.GetHostMeasurements(ctx, p.GroupId, p.ProcessId) + req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) + + r, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to fetch process metrics: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("failed to fetch process metrics: %w", err) + } + if r == nil || !r.HasMeasurements() { + return nil, fmt.Errorf("no metrics for process %q", p.ProcessId) + } + return r, nil +} diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go b/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go new file mode 100644 index 0000000..52da64f --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go @@ -0,0 +1,91 @@ +package metrics + +import ( + "context" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" + "testing" + "time" +) + +// fixed timestamp for tests +var fixedTS = "2025-01-01T12:00:00Z" + +// parseTS wraps time.Parse and flags error on test failure +func parseTS(t *testing.T, ts string) time.Time { + t.Helper() + parsed, err := time.Parse(time.RFC3339, ts) + require.NoError(t, err) + return parsed +} + +// ----------------------------------------------------------------------------- +// Integration tests against test HTTP server +// ----------------------------------------------------------------------------- +// TODO: Implement integration tests + +// ----------------------------------------------------------------------------- +// Unit‐level tests against SDK mocks +// ----------------------------------------------------------------------------- + +func TestFetchProcessMetrics_Unit(t *testing.T) { + t.Parallel() + ctx := context.Background() + + cases := []struct { + name string + view *admin.ApiMeasurementsGeneralViewAtlas + wantErr bool + wantCount int + }{ + { + name: "Happy path returns data", + view: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{{ + Name: admin.PtrString("PROCESS_METRIC"), + DataPoints: &[]admin.MetricDataPointAtlas{{ + Timestamp: admin.PtrTime(parseTS(t, fixedTS)), + Value: admin.PtrFloat32(1.23)}}}}}, + wantCount: 1, + }, + { + name: "No available data returns error", + view: &admin.ApiMeasurementsGeneralViewAtlas{}, + wantErr: true, + }, + } + + var baseProcess = admin.GetHostMeasurementsApiParams{ + GroupId: "gID", + ProcessId: "pID", + Granularity: admin.PtrString("PT1H"), + Period: admin.PtrString("P1D"), + M: &[]string{"METRIC"}, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + mockSvc.EXPECT(). + GetHostMeasurements(mock.Anything, baseProcess.GroupId, baseProcess.ProcessId). + Return(admin.GetHostMeasurementsApiRequest{ApiService: mockSvc}).Once() + mockSvc.EXPECT(). + GetHostMeasurementsExecute(mock.Anything). + Return(tc.view, nil, nil).Once() + + result, err := FetchProcessMetrics(ctx, mockSvc, &baseProcess) + + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) + require.Len(t, *result.Measurements, tc.wantCount) + }) + } +} diff --git a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go b/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go deleted file mode 100644 index a315f65..0000000 --- a/usage-examples/go/atlas-sdk-go/internal/secrets_loader.go +++ /dev/null @@ -1,41 +0,0 @@ -package internal - -import ( - "fmt" - "github.com/joho/godotenv" - "log" - "os" -) - -type Secrets struct { - MongoDBUser string `json:"MONGODB_USER_NAME"` // :remove: - MongoDBPassword string `json:"MONGODB_PASSWORD"` // :remove: - AtlasAPIKey string `json:"MONGODB_ATLAS_PUBLIC_API_KEY"` // :remove: - AtlasAPISecret string `json:"MONGODB_ATLAS_PRIVATE_KEY"` // :remove: - ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` - ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` -} - -// LoadSecrets loads .env file variables to use in the application -func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load("./.env"); err != nil { - log.Println("No .env file found") - } - secrets := &Secrets{ - MongoDBUser: os.Getenv("MONGODB_USER_NAME"), // :remove: - MongoDBPassword: os.Getenv("MONGODB_PASSWORD"), // :remove: - AtlasAPIKey: os.Getenv("MONGODB_ATLAS_PUBLIC_KEY"), // :remove: - AtlasAPISecret: os.Getenv("MONGODB_ATLAS_PRIVATE_KEY"), // :remove: - ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), - ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), - } - return secrets, nil -} - -// CheckRequiredEnv verifies that required environment variables are set -func (s *Secrets) CheckRequiredEnv() error { - if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { - return fmt.Errorf("service account client credentials must be set") - } - return nil -} diff --git a/usage-examples/go/atlas-sdk-go/internal/utils.go b/usage-examples/go/atlas-sdk-go/internal/utils.go new file mode 100644 index 0000000..b1aff89 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/internal/utils.go @@ -0,0 +1,49 @@ +package internal + +import ( + "io" + "log" + "os" + "path/filepath" +) + +// SafeClose closes c and logs a warning on error. +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("warning: close failed: %v", err) + } + } +} + +// SafeCopy copies src → dst and propagates any error (after logging). +func SafeCopy(dst io.Writer, src io.Reader) error { + if _, err := io.Copy(dst, src); err != nil { + log.Printf("warning: copy failed: %v", err) + return err + } + return nil +} + +// :remove-start: + +// SafeDelete removes files generated in the specified directory. +func SafeDelete(dir string) error { + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + if removeErr := os.Remove(path); removeErr != nil { + log.Printf("warning: failed to delete file %s: %v", path, removeErr) + } + } + return nil + }) + if err != nil { + return err + } + return nil +} + +// :remove-end: diff --git a/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh new file mode 100755 index 0000000..c2b81c3 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat < [flags] + +If you run with **no arguments**, you’ll be prompted interactively. + +Commands: + snip Extract code examples from Bluehawk snippets + copy Copy sanitized project files + +Example (non‐interactive): + $(basename "$0") copy --ignore="tests/*.go" --rename='{"old.md":"new.md"}' +EOF + exit 1 +} + +# defaults +CMD="" +PROJECT=$(git rev-parse --show-toplevel) +INPUT_DIR="$PROJECT/usage-examples/go/atlas-sdk-go" +OUTPUT_DIR="$PROJECT/generated-usage-examples/go/atlas-sdk-go/" +STATE="" +IGNORE_PATTERNS=( + "README.md" + "scripts/" + "tests/" + ".*" + "logs/" + "*.gz" + "*.log" +) +RENAME_PATTERNS=('{"REPO_README.md":"README.md"}') + +# ─── Interactive mode ──────────────────────────────────────────────────────── +if [[ $# -eq 0 ]]; then + echo "=== Run Bluehawk ===" + + # 1) pick snip or copy + while true; do + read -rp "Enter command (snip/copy): " CMD + [[ "$CMD" == "snip" || "$CMD" == "copy" ]] && break + echo "enter 'snip' or 'copy'" + done + +STATE=$([[ "$CMD" == "snip" ]] && echo "" || echo "copy") +OUTPUT_DIR=$([[ "$CMD" == "snip" ]] && echo "$OUTPUT_DIR" || echo "$OUTPUT_DIR/project-copy") + + +IGNORE_ARGS=() +for pattern in "${IGNORE_PATTERNS[@]}"; do + IGNORE_ARGS+=(--ignore="$pattern") +done + +RENAME_ARGS=() +if [[ "$CMD" != "snip" ]]; then + for rule in "${RENAME_PATTERNS[@]}"; do + RENAME_ARGS+=(--rename="$rule") + done +fi + +# call .bluehawk with all the args +.bluehawk "$CMD" \ + --state="$STATE" \ + -o "$OUTPUT_DIR" \ + "${IGNORE_ARGS[@]}" \ + "${RENAME_ARGS[@]}" \ + "$INPUT_DIR" diff --git a/usage-examples/go/atlas-sdk-go/tests/mock_test.go b/usage-examples/go/atlas-sdk-go/tests/mock_test.go deleted file mode 100644 index 196d9c3..0000000 --- a/usage-examples/go/atlas-sdk-go/tests/mock_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package test - -// TODO Refactor tests using mock data - -import ( - "bytes" - "compress/gzip" - "context" - "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "testing" -) - -var ( - testGroupID = "test-group-id" - testHostName = "test-host-name" - testProcessID = "test-process-id" - testLogName = "mongodb" - testTimeStamp = "2023-01-01T00:00:00Z" - testPartition = "data" - testLogResponse = "log content" -) - -func TestMockAtlasClient_GetHostLogs_Download(t *testing.T) { - // Set up a Gzip.Writer - var buf bytes.Buffer - gz := gzip.NewWriter(&buf) - _, err := gz.Write([]byte(testLogResponse)) - assert.NoError(t, err) - err = gz.Close() - assert.NoError(t, err) - - // Initialize mock client with compressed log data stored in buffer - mockClient := &MockAtlasClient{ - FakeHostLogsResponse: buf.String(), - } - - ctx := context.Background() - params := &admin.GetHostLogsApiParams{} - - // Call GetHostLogs to download the log.gz file - resp, err := mockClient.GetHostLogs(ctx, params) - assert.NoError(t, err) - assert.NotNil(t, resp) - - // Read the downloaded log.gz file - gzReader, err := gzip.NewReader(resp) - assert.NoError(t, err) - defer func(gzReader *gzip.Reader) { - err := gzReader.Close() - if err != nil { - t.Errorf("failed to close gzip reader: %v", err) - } - }(gzReader) - - // Verify compressed data with the original log content - var result bytes.Buffer - _, err = io.Copy(&result, gzReader) - assert.NoError(t, err) - assert.Equal(t, testLogResponse, result.String()) -} - -func TestMockAtlasClient_GetHostLogs_Read(t *testing.T) { - mockClient := &MockAtlasClient{ - FakeHostLogsResponse: testLogResponse, - FakeHostLogsError: nil, - } - - ctx := context.Background() - params := &admin.GetHostLogsApiParams{ - GroupId: testGroupID, - HostName: testHostName, - LogName: testLogName, - } - - resp, err := mockClient.GetHostLogs(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - ActualLogResponse, err := io.ReadAll(resp) - if err != nil { - t.Fatalf("failed to read log content: %v", err) - } - - if string(ActualLogResponse) != testLogResponse { - t.Errorf("expected %s, got %s", testLogResponse, string(ActualLogResponse)) - } -} - -func TestMockAtlasClient_GetProcessMetrics(t *testing.T) { - expectedMetricName := "DB_DATA_SIZE_TOTAL" - parsedTime, _ := admin.StringToTime(testTimeStamp) - parsedTimeValue := float32(100) - - mockClient := &MockAtlasClient{ - FakeProcessMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{ - { - Name: admin.PtrString(expectedMetricName), - DataPoints: &[]admin.MetricDataPointAtlas{ - {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, - }, - }, - }, - }, - FakeProcessMetricsError: nil, - } - - ctx := context.Background() - params := &admin.GetHostMeasurementsApiParams{ - GroupId: testGroupID, - ProcessId: testProcessID, - } - - resp, _, err := mockClient.GetProcessMetrics(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if resp.HasMeasurements() == false { - t.Errorf("expected measurements, got none") - } - - measurements := resp.GetMeasurements() - actualMetricName := measurements[0].GetName() - if actualMetricName != expectedMetricName { - t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) - } -} - -func TestMockAtlasClient_GetDiskMetrics(t *testing.T) { - - expectedMetricName := "DISK_PARTITION_SPACE_FREE" - parsedTime, _ := admin.StringToTime(testTimeStamp) - parsedTimeValue := float32(500) - - mockClient := &MockAtlasClient{ - FakeDiskMetricsResponse: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{ - { - Name: admin.PtrString(expectedMetricName), - DataPoints: &[]admin.MetricDataPointAtlas{ - {Timestamp: admin.PtrTime(parsedTime), Value: admin.PtrFloat32(parsedTimeValue)}, - }, - }, - }, - }, - FakeDiskMetricsError: nil, - } - - ctx := context.Background() - params := &admin.GetDiskMeasurementsApiParams{ - GroupId: testGroupID, - ProcessId: testProcessID, - PartitionName: testPartition, - } - - resp, _, err := mockClient.GetDiskMetrics(ctx, params) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if resp.HasMeasurements() == false { - t.Errorf("expected measurements, got none") - } - - measurements := resp.GetMeasurements() - actualMetricName := measurements[0].GetName() - if actualMetricName != expectedMetricName { - t.Errorf("expected %s, got %s", expectedMetricName, actualMetricName) - } -} diff --git a/usage-examples/go/atlas-sdk-go/tests/mocks.go b/usage-examples/go/atlas-sdk-go/tests/mocks.go deleted file mode 100644 index c24b6ab..0000000 --- a/usage-examples/go/atlas-sdk-go/tests/mocks.go +++ /dev/null @@ -1,44 +0,0 @@ -package test - -import ( - "context" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "net/http" - "strings" -) - -// TODO Refactor to use generated mock client - -// MockAtlasClient is a fake implementation of AtlasClient for testing. -type MockAtlasClient struct { - FakeHostLogsResponse string - FakeHostLogsError error - FakeProcessMetricsResponse *admin.ApiMeasurementsGeneralViewAtlas - FakeProcessMetricsError error - FakeDiskMetricsResponse *admin.ApiMeasurementsGeneralViewAtlas - FakeDiskMetricsError error -} - -func (m *MockAtlasClient) GetHostLogs(context.Context, *admin.GetHostLogsApiParams) (io.ReadCloser, error) { - if m.FakeHostLogsError != nil { - return nil, m.FakeHostLogsError - } - return io.NopCloser(strings.NewReader(m.FakeHostLogsResponse)), nil -} - -// GetProcessMetrics returns fake process metrics or an error. -func (m *MockAtlasClient) GetProcessMetrics(context.Context, *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { - if m.FakeProcessMetricsError != nil { - return nil, nil, m.FakeProcessMetricsError - } - return m.FakeProcessMetricsResponse, nil, nil -} - -// GetDiskMetrics returns fake disk metrics or an error. -func (m *MockAtlasClient) GetDiskMetrics(context.Context, *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, *http.Response, error) { - if m.FakeDiskMetricsError != nil { - return nil, nil, m.FakeDiskMetricsError - } - return m.FakeDiskMetricsResponse, nil, nil -} diff --git a/usage-examples/go/atlas-sdk-go/tests/run_cmd.sh b/usage-examples/go/atlas-sdk-go/tests/run_cmd.sh deleted file mode 100755 index 93d2175..0000000 --- a/usage-examples/go/atlas-sdk-go/tests/run_cmd.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Check if an action is provided -if [ -z "$1" ]; then - echo "Usage: $0 " - exit 1 -fi - -ACTION=$1 -MAIN_FILE="cmd/$ACTION/main.go" - -# Check if the main.go file exists for the given action -if [ ! -f "$MAIN_FILE" ]; then - echo "Error: $MAIN_FILE does not exist." - exit 1 -fi - -# Run the main.go file -go run "$MAIN_FILE" diff --git a/usage-examples/go/atlas-sdk-go/tests/utils.go b/usage-examples/go/atlas-sdk-go/tests/utils.go deleted file mode 100644 index d8b5f91..0000000 --- a/usage-examples/go/atlas-sdk-go/tests/utils.go +++ /dev/null @@ -1,42 +0,0 @@ -package test - -import ( - "fmt" - "log" - "os" - "path/filepath" -) - -// deleteFile deletes a specified file during cleanup after tests. -func deleteFile(fileName string) error { - err := os.Remove(fileName) - log.Printf("Deleting file %s", fileName) - if err != nil { - return fmt.Errorf("failed to delete file %s: %w", fileName, err) - } - return nil -} - -// CleanupFiles deletes generated *.gz and *.log files from the project root directory -func CleanupFiles() error { - projectRoot := "./" - var filesToDelete []string - - for _, pattern := range []string{"*.gz", "*.log"} { - files, err := filepath.Glob(filepath.Join(projectRoot, pattern)) - if err != nil { - return fmt.Errorf("failed to glob %q: %w", pattern, err) - } - filesToDelete = append(filesToDelete, files...) - } - - for _, file := range filesToDelete { - if err := os.Remove(file); err != nil { - log.Printf("Failed to delete file %s: %v", file, err) - } else { - log.Printf("Deleted %s", file) - } - } - - return nil -} From f5414b38f25aa202b88a2b68d3e4d4cba182e157 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Mon, 5 May 2025 12:59:46 -0400 Subject: [PATCH 20/22] Run bluehawk copy --- config.json | 58 +-------- .../go/19March2025GoRootTest.go | 1 - .../copied-project/cmd/get_logs/main.go | 110 ------------------ .../cmd/get_metrics_disk/main.go | 63 ---------- .../cmd/get_metrics_process/main.go | 66 ----------- .../copied-project/internal/auth/auth.go | 43 ------- .../copied-project/internal/config_loader.go | 56 --------- .../copied-project/internal/secrets_loader.go | 33 ------ .../go/atlas-sdk-go/main.snippet.get-logs.go | 61 ++++++++++ .../main.snippet.get-metrics-dev.go | 46 ++++++++ .../main.snippet.get-metrics-prod.go | 51 ++++++++ .../go/atlas-sdk-go/project-copy/README.md | 24 ++++ .../project-copy/cmd/get_logs/main.go | 60 ++++++++++ .../project-copy/cmd/get_metrics_disk/main.go | 45 +++++++ .../cmd/get_metrics_process/main.go | 50 ++++++++ .../configs/config.json | 0 .../{copied-project => project-copy}/go.mod | 1 + .../{copied-project => project-copy}/go.sum | 2 + .../project-copy/internal/auth/client.go | 25 ++++ .../project-copy/internal/config/json.go | 49 ++++++++ .../project-copy/internal/config/loader.go | 20 ++++ .../project-copy/internal/config/secrets.go | 38 ++++++ .../project-copy/internal/logs/fetch.go | 26 +++++ .../project-copy/internal/logs/fetch_test.go | 83 +++++++++++++ .../project-copy/internal/logs/file.go | 23 ++++ .../project-copy/internal/logs/file_test.go | 33 ++++++ .../project-copy/internal/logs/gzip.go | 34 ++++++ .../project-copy/internal/logs/gzip_test.go | 50 ++++++++ .../project-copy/internal/metrics/disk.go | 32 +++++ .../internal/metrics/disk_test.go | 77 ++++++++++++ .../project-copy/internal/metrics/process.go | 31 +++++ .../internal/metrics/process_test.go | 91 +++++++++++++++ .../project-copy/internal/utils.go | 27 +++++ generated-usage-examples/go/deletemeplease.go | 3 - .../go/v2/19marchtestv2Folder.go | 3 - .../go/atlas-sdk-go/.bluehawk/copy.sh | 41 ------- .../go/atlas-sdk-go/.bluehawk/snip.sh | 55 --------- usage-examples/go/atlas-sdk-go/REPO_README.md | 29 +---- .../go/atlas-sdk-go/cmd/get_logs/main.go | 4 +- .../atlas-sdk-go/cmd/get_metrics_disk/main.go | 2 +- .../cmd/get_metrics_process/main.go | 2 +- .../go/atlas-sdk-go/configs/.config.json | 7 -- .../atlas-sdk-go/internal/config/secrets.go | 12 -- .../go/atlas-sdk-go/scripts/bluehawk.sh | 37 +++--- usage-examples/go/newgotestfile.go | 14 --- usage-examples/go/ohhai_detete_me | 14 --- usage-examples/go/v22testfile2.go | 14 --- 47 files changed, 1005 insertions(+), 641 deletions(-) delete mode 100644 generated-usage-examples/go/19March2025GoRootTest.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_logs/main.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_disk/main.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_process/main.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/internal/auth/auth.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/internal/config_loader.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/copied-project/internal/secrets_loader.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/README.md create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go rename generated-usage-examples/go/atlas-sdk-go/{copied-project => project-copy}/configs/config.json (100%) rename generated-usage-examples/go/atlas-sdk-go/{copied-project => project-copy}/go.mod (90%) rename generated-usage-examples/go/atlas-sdk-go/{copied-project => project-copy}/go.sum (91%) create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go delete mode 100644 generated-usage-examples/go/deletemeplease.go delete mode 100644 generated-usage-examples/go/v2/19marchtestv2Folder.go delete mode 100644 usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh delete mode 100755 usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh delete mode 100644 usage-examples/go/atlas-sdk-go/configs/.config.json delete mode 100644 usage-examples/go/newgotestfile.go delete mode 100644 usage-examples/go/ohhai_detete_me delete mode 100644 usage-examples/go/v22testfile2.go diff --git a/config.json b/config.json index 10fdfb3..be899e6 100644 --- a/config.json +++ b/config.json @@ -1,67 +1,11 @@ [ { "notes": "Copy atlas-sdk-go project files to user-facing Atlas Architecture Center artifact repo root", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/", + "source_directory" : "generated-usage-examples/go/atlas-sdk-go/project-copy/", "target_repo" : "atlas-architecture-go-sdk", "target_branch" : "main", "target_directory" : "." }, - { - "notes": "atlas-sdk-go/copied-project/cmd subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/cmd", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "cmd" - }, - { - "notes": "atlas-sdk-go/copied-project/cmd/get_logs subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_logs", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "cmd/get_logs" - }, - { - "notes": "atlas-sdk-go/copied-project/cmd/get_metrics_process subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_process", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "cmd/get_metrics_process" - }, - { - "notes": "atlas-sdk-go/copied-project/cmd/get_metrics_disk subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_disk", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "cmd/get_metrics_disk" - }, - { - "notes": "atlas-sdk-go/copied-project/configs", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/configs", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "configs" - }, - { - "notes": "atlas-sdk-go/copied-project/internal subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/internal", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "internal" - }, - { - "notes": "atlas-sdk-go/copied-project/internal/auth subdirectory", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/internal/auth", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "main", - "target_directory" : "internal/auth" - }, - { - "notes": "Copy atlas-sdk-go project files to user-facing Atlas Architecture Center artifact repo root", - "source_directory" : "generated-usage-examples/go/atlas-sdk-go/copied-project/", - "target_repo" : "atlas-architecture-go-sdk", - "target_branch" : "copy-test-2", - "target_directory" : "." - }, { "notes": "Example config for copying files from a directory to another repo", "source_directory" : "generated-examples", diff --git a/generated-usage-examples/go/19March2025GoRootTest.go b/generated-usage-examples/go/19March2025GoRootTest.go deleted file mode 100644 index 083fb85..0000000 --- a/generated-usage-examples/go/19March2025GoRootTest.go +++ /dev/null @@ -1 +0,0 @@ -This lives in the Go root diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_logs/main.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_logs/main.go deleted file mode 100644 index 82a5234..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_logs/main.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "compress/gzip" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "io" - "log" - "os" - "strings" -) - -// getHostLogs downloads a compressed .gz file that contains the MongoDB logs for -// the specified host in your project. -func getHostLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams) (string, error) { - logFileName := fmt.Sprintf("logs_%s_%s.gz", params.GroupId, params.HostName) - fmt.Printf("Fetching %s log for host %s in project %s\n", params.LogName, params.HostName, params.GroupId) - - if err := downloadLogs(ctx, atlasClient, params, logFileName); err != nil { - return "", err - } - - fmt.Printf("Logs saved to %s\n", logFileName) - return logFileName, nil -} - -func SafeClose(c io.Closer) { - if c != nil { - if err := c.Close(); err != nil { - log.Printf("Warning: failed to close resource: %v", err) - } - } -} - -func downloadLogs(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostLogsApiParams, filePath string) error { - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostLogsWithParams(ctx, params).Execute() - if err != nil { - return fmt.Errorf("fetch logs: %w", err) - } - defer SafeClose(resp) - - file, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("create %q: %w", filePath, err) - } - defer SafeClose(file) - - if _, err := io.Copy(file, resp); err != nil { - return fmt.Errorf("write to %q: %w", filePath, err) - } - - return nil -} - -func unzipGzFile(srcPath, destPath string) error { - srcFile, err := os.Open(srcPath) - if err != nil { - return fmt.Errorf("open gz file: %w", err) - } - defer SafeClose(srcFile) - - gzReader, err := gzip.NewReader(srcFile) - if err != nil { - return fmt.Errorf("create gzip reader: %w", err) - } - defer SafeClose(gzReader) - - destFile, err := os.Create(destPath) - if err != nil { - return fmt.Errorf("create destination file: %w", err) - } - defer SafeClose(destFile) - - if _, err := io.Copy(destFile, gzReader); err != nil { - return fmt.Errorf("unzip copy error: %w", err) - } - - fmt.Printf("Unzipped logs to %s\n", destPath) - return nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - client, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - params := &admin.GetHostLogsApiParams{ - GroupId: config.ProjectID, - HostName: config.HostName, - LogName: "mongodb", // Type of log ("mongodb" or "mongos") - } - - logFileName, err := getHostLogs(ctx, *client, params) - if err != nil { - log.Fatalf("Failed to download logs: %v", err) - } - - plainTextLog := strings.TrimSuffix(logFileName, ".gz") + ".log" - if err := unzipGzFile(logFileName, plainTextLog); err != nil { - log.Fatalf("Failed to unzip log file: %v", err) - } - -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_disk/main.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_disk/main.go deleted file mode 100644 index fe61acf..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_disk/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getDiskMetrics fetches metrics for a specified disk partition in a project and prints results to the console -func getDiskMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetDiskMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for partition: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for partition %s in project %s", params.PartitionName, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch disk metrics using the following parameters: - partitionName := "data" - diskMetricsGranularity := admin.PtrString("P1D") - diskMetricsPeriod := admin.PtrString("P1D") - diskMetrics := []string{ - "DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED", - } - - diskMeasurementsParams := &admin.GetDiskMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - PartitionName: partitionName, - M: &diskMetrics, - Granularity: diskMetricsGranularity, - Period: diskMetricsPeriod, - } - _, err = getDiskMetrics(ctx, *atlasClient, diskMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching disk metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_process/main.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_process/main.go deleted file mode 100644 index e957167..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/cmd/get_metrics_process/main.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "atlas-sdk-go/internal/auth" - "context" - "encoding/json" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" -) - -// getProcessMetrics fetches metrics for a specified host process in a project and prints results to the console -func getProcessMetrics(ctx context.Context, atlasClient admin.APIClient, params *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - fmt.Printf("Fetching metrics for host process %s in project %s", params.ProcessId, params.GroupId) - - resp, _, err := atlasClient.MonitoringAndLogsApi.GetHostMeasurementsWithParams(ctx, params).Execute() - if err != nil { - if apiError, ok := admin.AsError(err); ok { - return nil, fmt.Errorf("failed to get metrics for process in host: %s (API error: %v)", err, apiError.GetDetail()) - } - return nil, fmt.Errorf("failed to get metrics: %w", err) - } - - if resp == nil || resp.HasMeasurements() == false { - return nil, fmt.Errorf("no metrics found for host process %s in project %s", params.ProcessId, params.GroupId) - } - jsonData, err := json.MarshalIndent(resp, "", " ") - if err != nil { - return nil, fmt.Errorf("failed to marshal response: %w", err) - } - fmt.Println(string(jsonData)) - return resp, nil -} - -func main() { - ctx := context.Background() - - // Create an Atlas client authenticated using OAuth2 with service account credentials - atlasClient, _, config, err := auth.CreateAtlasClient() - if err != nil { - log.Fatalf("Failed to create Atlas client: %v", err) - } - - // Fetch process metrics using the following parameters: - processMetricGranularity := admin.PtrString("PT1H") - processMetricPeriod := admin.PtrString("P7D") - processMetrics := []string{ - "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", - "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", - "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", - "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", - "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", - } - hostMeasurementsParams := &admin.GetHostMeasurementsApiParams{ - GroupId: config.ProjectID, - ProcessId: config.ProcessID, - M: &processMetrics, - Granularity: processMetricGranularity, - Period: processMetricPeriod, - } - _, err = getProcessMetrics(ctx, *atlasClient, hostMeasurementsParams) - if err != nil { - fmt.Printf("Error fetching host process metrics: %v", err) - } -} - diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/auth/auth.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/auth/auth.go deleted file mode 100644 index 2580744..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/auth/auth.go +++ /dev/null @@ -1,43 +0,0 @@ -package auth - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "go.mongodb.org/atlas-sdk/v20250219001/admin" -) - -const filePath = "./configs/config.json" - -// CreateAtlasClient initializes and returns an authenticated Atlas API client -// using OAuth2 with service account credentials. -func CreateAtlasClient() (*admin.APIClient, *internal.Secrets, *internal.Config, error) { - - var secrets, err = internal.LoadSecrets() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load secrets: %w", err) - } - if err := secrets.CheckRequiredEnv(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid .env: %w", err) - } - - config, err := internal.LoadConfig(filePath) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to load config file: %w", err) - } - config.SetDefaults() - if err := config.CheckRequiredFields(); err != nil { - return nil, nil, nil, fmt.Errorf("invalid config: %w", err) - } - - ctx := context.Background() - atlasClient, err := admin.NewClient( - admin.UseBaseURL(config.BaseURL), - admin.UseOAuthAuth(ctx, secrets.ServiceAccountID, secrets.ServiceAccountSecret), - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating SDK client: %w", err) - } - - return atlasClient, secrets, config, nil -} diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/config_loader.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/config_loader.go deleted file mode 100644 index d75df81..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/config_loader.go +++ /dev/null @@ -1,56 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "os" - "strings" -) - -type Config struct { - BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` - OrgID string `json:"ATLAS_ORG_ID"` - ProjectID string `json:"ATLAS_PROJECT_ID"` - ClusterName string `json:"ATLAS_CLUSTER_NAME"` - HostName string - ProcessID string `json:"ATLAS_PROCESS_ID"` -} - -// LoadConfig loads a JSON config file to make it globally available -func LoadConfig(filePath string) (*Config, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("error opening config file: %w", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Println("Error closing file") - } - }(file) - - var config Config - decoder := json.NewDecoder(file) - if err := decoder.Decode(&config); err != nil { - return nil, fmt.Errorf("error decoding config file: %w", err) - } - return &config, nil -} - -// SetDefaults sets default values if specified config variables are empty -func (c *Config) SetDefaults() { - if c.BaseURL == "" { - c.BaseURL = "https://cloud.mongodb.com" - } - if c.HostName == "" { - c.HostName = strings.Split(c.ProcessID, ":")[0] - } -} - -// CheckRequiredFields verifies that required Atlas fields are set in the config file -func (c *Config) CheckRequiredFields() error { - if c.OrgID == "" || c.ProjectID == "" { - return fmt.Errorf("missing required Atlas fields in config file") - } - return nil -} diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/secrets_loader.go b/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/secrets_loader.go deleted file mode 100644 index 19f9d49..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/internal/secrets_loader.go +++ /dev/null @@ -1,33 +0,0 @@ -package internal - -import ( - "fmt" - "github.com/joho/godotenv" - "log" - "os" -) - -type Secrets struct { - ServiceAccountID string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_ID"` - ServiceAccountSecret string `json:"MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"` -} - -// LoadSecrets loads .env file variables to use in the application -func LoadSecrets() (*Secrets, error) { - if err := godotenv.Load("./.env"); err != nil { - log.Println("No .env file found") - } - secrets := &Secrets{ - ServiceAccountID: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_ID"), - ServiceAccountSecret: os.Getenv("MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET"), - } - return secrets, nil -} - -// CheckRequiredEnv verifies that required environment variables are set -func (s *Secrets) CheckRequiredEnv() error { - if s.ServiceAccountID == "" || s.ServiceAccountSecret == "" { - return fmt.Errorf("service account client credentials must be set") - } - return nil -} diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go new file mode 100644 index 0000000..8864477 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go @@ -0,0 +1,61 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" + "context" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" + "os" + "path/filepath" + "time" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetHostLogsApiParams{ + GroupId: cfg.ProjectID, + HostName: cfg.HostName, + LogName: "mongodb", + } + ts := time.Now().Format("20060102_150405") + base := fmt.Sprintf("%s_%s_%s", p.HostName, p.LogName, ts) + outDir := "logs" + os.MkdirAll(outDir, 0o755) + gzPath := filepath.Join(outDir, base+".gz") + txtPath := filepath.Join(outDir, base+".txt") + + rc, err := logs.FetchHostLogs(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("download logs: %v", err) + } + defer internal.SafeClose(rc) + + if err := logs.WriteToFile(rc, gzPath); err != nil { + log.Fatalf("save gz: %v", err) + } + fmt.Println("Saved compressed log to", gzPath) + + if err := logs.DecompressGzip(gzPath, txtPath); err != nil { + log.Fatalf("decompress: %v", err) + } + fmt.Println("Uncompressed log to", txtPath) + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go new file mode 100644 index 0000000..1d32483 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go @@ -0,0 +1,46 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" + "context" + "encoding/json" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetDiskMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + PartitionName: "data", + M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, + Granularity: admin.PtrString("P1D"), + Period: admin.PtrString("P1D"), + } + + view, err := metrics.FetchDiskMetrics(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("disk metrics: %v", err) + } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go new file mode 100644 index 0000000..3fd1d51 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go @@ -0,0 +1,51 @@ +// See entire project at https://github.com/mongodb/atlas-architecture-go-sdk +package main + +import ( + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" + "context" + "encoding/json" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetHostMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + M: &[]string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + }, + Granularity: admin.PtrString("PT1H"), + Period: admin.PtrString("P7D"), + } + + view, err := metrics.FetchProcessMetrics(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("process metrics: %v", err) + } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/README.md b/generated-usage-examples/go/atlas-sdk-go/project-copy/README.md new file mode 100644 index 0000000..ce2bbb0 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/README.md @@ -0,0 +1,24 @@ +# MongoDB Atlas Architecture Center Go SDK Code Examples + +This repository contains [Atlas Go SDK](https://www.mongodb.com/docs/atlas/sdk/) +code examples that follow recommendations in MongoDB's official +[Atlas Architecture Center documentation](https://www.mongodb.com/docs/atlas/architecture/current/). +You can run, download, and modify these code examples as starting points for +configuring your MongoDB Atlas architecture for your use case. + +## License + +This project is licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). + +## Issues + +To report an issue with any of these code examples, please leave feedback +through the corresponding documentation page in the +[MongoDB Atlas Architecture Center](https://www.mongodb.com/docs/atlas/architecture/current/). +Using the `Rate This Page` button, you can add a comment about the issue after +leaving a star rating. + +## Contributing + +We are not currently accepting public contributions to this repository at this +time. \ No newline at end of file diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go new file mode 100644 index 0000000..6b62aa0 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" + "context" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" + "os" + "path/filepath" + "time" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetHostLogsApiParams{ + GroupId: cfg.ProjectID, + HostName: cfg.HostName, + LogName: "mongodb", + } + ts := time.Now().Format("20060102_150405") + base := fmt.Sprintf("%s_%s_%s", p.HostName, p.LogName, ts) + outDir := "logs" + os.MkdirAll(outDir, 0o755) + gzPath := filepath.Join(outDir, base+".gz") + txtPath := filepath.Join(outDir, base+".txt") + + rc, err := logs.FetchHostLogs(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("download logs: %v", err) + } + defer internal.SafeClose(rc) + + if err := logs.WriteToFile(rc, gzPath); err != nil { + log.Fatalf("save gz: %v", err) + } + fmt.Println("Saved compressed log to", gzPath) + + if err := logs.DecompressGzip(gzPath, txtPath); err != nil { + log.Fatalf("decompress: %v", err) + } + fmt.Println("Uncompressed log to", txtPath) + +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go new file mode 100644 index 0000000..b508bf8 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" + "context" + "encoding/json" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetDiskMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + PartitionName: "data", + M: &[]string{"DISK_PARTITION_SPACE_FREE", "DISK_PARTITION_SPACE_USED"}, + Granularity: admin.PtrString("P1D"), + Period: admin.PtrString("P1D"), + } + + view, err := metrics.FetchDiskMetrics(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("disk metrics: %v", err) + } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go new file mode 100644 index 0000000..ffbf432 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" + "context" + "encoding/json" + "fmt" + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "log" +) + +func main() { + _ = godotenv.Load() + secrets, cfg, err := config.LoadAll("configs/config.json") + if err != nil { + log.Fatalf("config load: %v", err) + } + + sdk, err := auth.NewClient(cfg, secrets) + if err != nil { + log.Fatalf("client init: %v", err) + } + + ctx := context.Background() + p := &admin.GetHostMeasurementsApiParams{ + GroupId: cfg.ProjectID, + ProcessId: cfg.ProcessID, + M: &[]string{ + "OPCOUNTER_INSERT", "OPCOUNTER_QUERY", "OPCOUNTER_UPDATE", "TICKETS_AVAILABLE_READS", + "TICKETS_AVAILABLE_WRITE", "CONNECTIONS", "QUERY_TARGETING_SCANNED_OBJECTS_PER_RETURNED", + "QUERY_TARGETING_SCANNED_PER_RETURNED", "SYSTEM_CPU_GUEST", "SYSTEM_CPU_IOWAIT", + "SYSTEM_CPU_IRQ", "SYSTEM_CPU_KERNEL", "SYSTEM_CPU_NICE", "SYSTEM_CPU_SOFTIRQ", + "SYSTEM_CPU_STEAL", "SYSTEM_CPU_USER", + }, + Granularity: admin.PtrString("PT1H"), + Period: admin.PtrString("P7D"), + } + + view, err := metrics.FetchProcessMetrics(ctx, sdk.MonitoringAndLogsApi, p) + if err != nil { + log.Fatalf("process metrics: %v", err) + } + + out, _ := json.MarshalIndent(view, "", " ") + fmt.Println(string(out)) +} + diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/configs/config.json b/generated-usage-examples/go/atlas-sdk-go/project-copy/configs/config.json similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/copied-project/configs/config.json rename to generated-usage-examples/go/atlas-sdk-go/project-copy/configs/config.json diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/go.mod b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod similarity index 90% rename from generated-usage-examples/go/atlas-sdk-go/copied-project/go.mod rename to generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod index 1a74333..f26b6af 100644 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/go.mod +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod @@ -12,6 +12,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/mongodb-forks/digest v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect golang.org/x/oauth2 v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/generated-usage-examples/go/atlas-sdk-go/copied-project/go.sum b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum similarity index 91% rename from generated-usage-examples/go/atlas-sdk-go/copied-project/go.sum rename to generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum index f7ec5e3..01a0f83 100644 --- a/generated-usage-examples/go/atlas-sdk-go/copied-project/go.sum +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum @@ -8,6 +8,8 @@ github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKk github.com/mongodb-forks/digest v1.1.0/go.mod h1:rb+EX8zotClD5Dj4NdgxnJXG9nwrlx3NWKJ8xttz1Dg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go new file mode 100644 index 0000000..eb28c0d --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go @@ -0,0 +1,25 @@ +package auth + +import ( + "atlas-sdk-go/internal/config" + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// NewClient initializes and returns an authenticated Atlas API client +// using OAuth2 with service account credentials (recommended) +func NewClient(cfg *config.Config, secrets *config.Secrets) (*admin.APIClient, error) { + sdk, err := admin.NewClient( + admin.UseBaseURL(cfg.BaseURL), + admin.UseOAuthAuth(context.Background(), + secrets.ServiceAccountID, + secrets.ServiceAccountSecret, + ), + ) + if err != nil { + return nil, fmt.Errorf("create atlas client: %w", err) + } + return sdk, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go new file mode 100644 index 0000000..d89bffd --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go @@ -0,0 +1,49 @@ +package config + +import ( + "atlas-sdk-go/internal" + "encoding/json" + "fmt" + "os" + "strings" +) + +type Config struct { + BaseURL string `json:"MONGODB_ATLAS_BASE_URL"` + OrgID string `json:"ATLAS_ORG_ID"` + ProjectID string `json:"ATLAS_PROJECT_ID"` + ClusterName string `json:"ATLAS_CLUSTER_NAME"` + HostName string + ProcessID string `json:"ATLAS_PROCESS_ID"` +} + +func LoadConfig(path string) (*Config, error) { + f, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("open config %s: %w", path, err) + } + defer internal.SafeClose(f) + + var c Config + if err := json.NewDecoder(f).Decode(&c); err != nil { + return nil, fmt.Errorf("decode %s: %w", path, err) + } + + // defaults + if c.BaseURL == "" { + c.BaseURL = "https://cloud.mongodb.com" + } + if c.HostName == "" { + // Go 1.18+: + if host, _, ok := strings.Cut(c.ProcessID, ":"); ok { + c.HostName = host + } + } + + // required + if c.OrgID == "" || c.ProjectID == "" { + return nil, fmt.Errorf("ATLAS_ORG_ID and ATLAS_PROJECT_ID are required") + } + + return &c, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go new file mode 100644 index 0000000..6cad472 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go @@ -0,0 +1,20 @@ +package config + +import ( + "fmt" +) + +// LoadAll loads secrets and config from the specified paths +func LoadAll(configPath string) (*Secrets, *Config, error) { + s, err := LoadSecrets() + if err != nil { + return nil, nil, fmt.Errorf("loading secrets: %w", err) + } + + c, err := LoadConfig(configPath) + if err != nil { + return nil, nil, fmt.Errorf("loading config: %w", err) + } + + return s, c, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go new file mode 100644 index 0000000..16dbeb2 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go @@ -0,0 +1,38 @@ +package config + +import ( + "fmt" + "os" + "strings" +) + +const ( + EnvSAClientID = "MONGODB_ATLAS_SERVICE_ACCOUNT_ID" + EnvSAClientSecret = "MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET" +) + +type Secrets struct { + ServiceAccountID string + ServiceAccountSecret string +} + +func LoadSecrets() (*Secrets, error) { + s := &Secrets{} + var missing []string + + look := func(key string, dest *string) { + if v, ok := os.LookupEnv(key); ok && v != "" { + *dest = v + } else { + missing = append(missing, key) + } + } + + look(EnvSAClientID, &s.ServiceAccountID) + look(EnvSAClientSecret, &s.ServiceAccountSecret) + + if len(missing) > 0 { + return nil, fmt.Errorf("missing required env vars: %s", strings.Join(missing, ", ")) + } + return s, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch.go new file mode 100644 index 0000000..48ca8bc --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch.go @@ -0,0 +1,26 @@ +package logs + +import ( + "context" + "fmt" + "io" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchHostLogs calls the Atlas SDK and returns the raw, compressed log stream. +func FetchHostLogs( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetHostLogsApiParams, +) (io.ReadCloser, error) { + req := sdk.GetHostLogs(ctx, p.GroupId, p.HostName, p.LogName) + rc, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to fetch logs: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("failed to fetch logs: %w", err) + } + return rc, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go new file mode 100644 index 0000000..b1c93b7 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go @@ -0,0 +1,83 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "context" + "fmt" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" +) + +func TestFetchHostLogs_Unit(t *testing.T) { + t.Parallel() + ctx := context.Background() + + // common params + params := &admin.GetHostLogsApiParams{ + GroupId: "gID", + HostName: "hName", + LogName: "mongodb", + } + + cases := []struct { + name string + setup func(m *mockadmin.MonitoringAndLogsApi) + wantErr bool + wantBody string + }{ + { + name: "API error", + wantErr: true, + setup: func(m *mockadmin.MonitoringAndLogsApi) { + m.EXPECT(). + GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). + Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() + m.EXPECT(). + GetHostLogsExecute(mock.Anything). + Return(nil, nil, fmt.Errorf("API error")).Once() + }, + }, + { + name: "Successful response", + wantErr: false, + wantBody: "log-data", + setup: func(m *mockadmin.MonitoringAndLogsApi) { + m.EXPECT(). + GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). + Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() + m.EXPECT(). + GetHostLogsExecute(mock.Anything). + Return(io.NopCloser(strings.NewReader("log-data")), nil, nil).Once() + }, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + tc.setup(mockSvc) + + rc, err := FetchHostLogs(ctx, mockSvc, params) + if tc.wantErr { + require.ErrorContainsf(t, err, "failed to fetch logs", "expected API error") + require.Nil(t, rc) + return + } + + require.NoError(t, err) + defer internal.SafeClose(rc) + + data, err := io.ReadAll(rc) + require.NoError(t, err) + require.Equal(t, tc.wantBody, string(data)) + }) + } +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go new file mode 100644 index 0000000..dfed136 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go @@ -0,0 +1,23 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "fmt" + "io" + "os" +) + +// WriteToFile copies everything from r into a new file at path. +// It will create (or truncate) that file. +func WriteToFile(r io.Reader, path string) error { + f, err := os.Create(path) + if err != nil { + return fmt.Errorf("create %s: %w", path, err) + } + defer internal.SafeClose(f) + + if err := internal.SafeCopy(f, r); err != nil { + return fmt.Errorf("write %s: %w", path, err) + } + return nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go new file mode 100644 index 0000000..8876d5a --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go @@ -0,0 +1,33 @@ +package logs + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWriteToFile_Success(t *testing.T) { + // create a temp dir and file + tmp := t.TempDir() + path := filepath.Join(tmp, "out.txt") + + input := "hello world" + r := strings.NewReader(input) + + require.NoError(t, WriteToFile(r, path)) + + // verify file exists and content matches + data, err := os.ReadFile(path) + require.NoError(t, err) + require.Equal(t, input, string(data)) +} + +func TestWriteToFile_Error(t *testing.T) { + path := "does-not-exist/out.txt" + err := WriteToFile(strings.NewReader("x"), path) + require.Error(t, err) + require.Contains(t, err.Error(), "create") +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go new file mode 100644 index 0000000..8505f93 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go @@ -0,0 +1,34 @@ +package logs + +import ( + "atlas-sdk-go/internal" + "compress/gzip" + "fmt" + "os" +) + +// DecompressGzip opens a .gz file and unpacks to specified destination. +func DecompressGzip(srcPath, destPath string) error { + srcFile, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open %s: %w", srcPath, err) + } + defer internal.SafeClose(srcFile) + + gzReader, err := gzip.NewReader(srcFile) + if err != nil { + return fmt.Errorf("gzip reader %s: %w", srcPath, err) + } + defer internal.SafeClose(gzReader) + + destFile, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("create %s: %w", destPath, err) + } + defer internal.SafeClose(destFile) + + if err := internal.SafeCopy(destFile, gzReader); err != nil { + return fmt.Errorf("decompress to %s: %w", destPath, err) + } + return nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go new file mode 100644 index 0000000..9cbee64 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go @@ -0,0 +1,50 @@ +package logs + +import ( + "compress/gzip" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecompressGzip_Success(t *testing.T) { + // create a temp dir and file + tmp := t.TempDir() + src := filepath.Join(tmp, "test.gz") + dst := filepath.Join(tmp, "test.txt") + + // create a gzip file and write some data to it + f, err := os.Create(src) + require.NoError(t, err) + + gz := gzip.NewWriter(f) + _, err = gz.Write([]byte("foobar")) + require.NoError(t, err) + require.NoError(t, gz.Close()) + require.NoError(t, f.Close()) + + // call the function to test + require.NoError(t, DecompressGzip(src, dst)) + + // verify the output + data, err := os.ReadFile(dst) + require.NoError(t, err) + require.Equal(t, "foobar", string(data)) +} + +func TestDecompressGzip_SourceNotFound(t *testing.T) { + tmp := t.TempDir() + src := filepath.Join(tmp, "nofile.gz") + dst := filepath.Join(tmp, "out.txt") + + // source file does not exist + err := DecompressGzip(src, dst) + require.Error(t, err) + require.Contains(t, err.Error(), "open") + + // destination file does not exist + _, err2 := os.Stat(dst) + require.True(t, os.IsNotExist(err2)) +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go new file mode 100644 index 0000000..cd9d597 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go @@ -0,0 +1,32 @@ +package metrics + +import ( + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchDiskMetrics returns measurements for a specified disk partition +func FetchDiskMetrics( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetDiskMeasurementsApiParams, +) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + req := sdk.GetDiskMeasurements(ctx, p.GroupId, p.PartitionName, p.ProcessId) + req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) + + r, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("fetch disk metrics: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("fetch disk metrics: %w", err) + } + if r == nil || !r.HasMeasurements() { + return nil, fmt.Errorf("no metrics for partition %q on process %q", + p.PartitionName, p.ProcessId) + } + return r, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go new file mode 100644 index 0000000..66d425f --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go @@ -0,0 +1,77 @@ +package metrics + +import ( + "context" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" + "testing" +) + +// ----------------------------------------------------------------------------- +// Integration tests against test HTTP server +// ----------------------------------------------------------------------------- +// TODO: Implement integration tests + +// ----------------------------------------------------------------------------- +// Unit‐level tests against SDK mocks +// ----------------------------------------------------------------------------- + +func TestFetchDiskMetrics(t *testing.T) { + t.Parallel() + ctx := context.Background() + + cases := []struct { + name string + view *admin.ApiMeasurementsGeneralViewAtlas + wantErr bool + wantCount int + }{ + {name: "Happy path returns data", + view: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{{ + Name: admin.PtrString("DISK_METRIC"), + DataPoints: &[]admin.MetricDataPointAtlas{{ + Timestamp: admin.PtrTime(parseTS(t, fixedTS)), + Value: admin.PtrFloat32(4.56)}}}}}, + wantCount: 1}, + {name: "No available data returns error", + view: &admin.ApiMeasurementsGeneralViewAtlas{}, + wantErr: true}, + } + + baseDisk := admin.GetDiskMeasurementsApiParams{ + GroupId: "gID", + PartitionName: "part", + ProcessId: "pID", + Granularity: admin.PtrString("P1D"), + Period: admin.PtrString("P1D"), + M: &[]string{"DISK_METRIC"}, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + // setup mock SDK + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + mockSvc.EXPECT(). + GetDiskMeasurements(mock.Anything, baseDisk.GroupId, baseDisk.PartitionName, baseDisk.ProcessId). + Return(admin.GetDiskMeasurementsApiRequest{ApiService: mockSvc}).Once() + mockSvc.EXPECT(). + GetDiskMeasurementsExecute(mock.Anything). + Return(tc.view, nil, nil).Once() + + result, err := FetchDiskMetrics(ctx, mockSvc, &baseDisk) + + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) + require.Len(t, *result.Measurements, tc.wantCount) + }) + } +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go new file mode 100644 index 0000000..53819b7 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go @@ -0,0 +1,31 @@ +package metrics + +import ( + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20250219001/admin" +) + +// FetchProcessMetrics returns measurements for a specified host process +func FetchProcessMetrics( + ctx context.Context, + sdk admin.MonitoringAndLogsApi, + p *admin.GetHostMeasurementsApiParams, +) (*admin.ApiMeasurementsGeneralViewAtlas, error) { + + req := sdk.GetHostMeasurements(ctx, p.GroupId, p.ProcessId) + req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) + + r, _, err := req.Execute() + if err != nil { + if apiErr, ok := admin.AsError(err); ok { + return nil, fmt.Errorf("failed to fetch process metrics: %w – %s", err, apiErr.GetDetail()) + } + return nil, fmt.Errorf("failed to fetch process metrics: %w", err) + } + if r == nil || !r.HasMeasurements() { + return nil, fmt.Errorf("no metrics for process %q", p.ProcessId) + } + return r, nil +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go new file mode 100644 index 0000000..52da64f --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go @@ -0,0 +1,91 @@ +package metrics + +import ( + "context" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" + "testing" + "time" +) + +// fixed timestamp for tests +var fixedTS = "2025-01-01T12:00:00Z" + +// parseTS wraps time.Parse and flags error on test failure +func parseTS(t *testing.T, ts string) time.Time { + t.Helper() + parsed, err := time.Parse(time.RFC3339, ts) + require.NoError(t, err) + return parsed +} + +// ----------------------------------------------------------------------------- +// Integration tests against test HTTP server +// ----------------------------------------------------------------------------- +// TODO: Implement integration tests + +// ----------------------------------------------------------------------------- +// Unit‐level tests against SDK mocks +// ----------------------------------------------------------------------------- + +func TestFetchProcessMetrics_Unit(t *testing.T) { + t.Parallel() + ctx := context.Background() + + cases := []struct { + name string + view *admin.ApiMeasurementsGeneralViewAtlas + wantErr bool + wantCount int + }{ + { + name: "Happy path returns data", + view: &admin.ApiMeasurementsGeneralViewAtlas{ + Measurements: &[]admin.MetricsMeasurementAtlas{{ + Name: admin.PtrString("PROCESS_METRIC"), + DataPoints: &[]admin.MetricDataPointAtlas{{ + Timestamp: admin.PtrTime(parseTS(t, fixedTS)), + Value: admin.PtrFloat32(1.23)}}}}}, + wantCount: 1, + }, + { + name: "No available data returns error", + view: &admin.ApiMeasurementsGeneralViewAtlas{}, + wantErr: true, + }, + } + + var baseProcess = admin.GetHostMeasurementsApiParams{ + GroupId: "gID", + ProcessId: "pID", + Granularity: admin.PtrString("PT1H"), + Period: admin.PtrString("P1D"), + M: &[]string{"METRIC"}, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + mockSvc := mockadmin.NewMonitoringAndLogsApi(t) + mockSvc.EXPECT(). + GetHostMeasurements(mock.Anything, baseProcess.GroupId, baseProcess.ProcessId). + Return(admin.GetHostMeasurementsApiRequest{ApiService: mockSvc}).Once() + mockSvc.EXPECT(). + GetHostMeasurementsExecute(mock.Anything). + Return(tc.view, nil, nil).Once() + + result, err := FetchProcessMetrics(ctx, mockSvc, &baseProcess) + + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) + require.Len(t, *result.Measurements, tc.wantCount) + }) + } +} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go new file mode 100644 index 0000000..7104dec --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go @@ -0,0 +1,27 @@ +package internal + +import ( + "io" + "log" + "os" + "path/filepath" +) + +// SafeClose closes c and logs a warning on error. +func SafeClose(c io.Closer) { + if c != nil { + if err := c.Close(); err != nil { + log.Printf("warning: close failed: %v", err) + } + } +} + +// SafeCopy copies src → dst and propagates any error (after logging). +func SafeCopy(dst io.Writer, src io.Reader) error { + if _, err := io.Copy(dst, src); err != nil { + log.Printf("warning: copy failed: %v", err) + return err + } + return nil +} + diff --git a/generated-usage-examples/go/deletemeplease.go b/generated-usage-examples/go/deletemeplease.go deleted file mode 100644 index 1930b2a..0000000 --- a/generated-usage-examples/go/deletemeplease.go +++ /dev/null @@ -1,3 +0,0 @@ -delete me. I'm a test file and not even a golang file! - - diff --git a/generated-usage-examples/go/v2/19marchtestv2Folder.go b/generated-usage-examples/go/v2/19marchtestv2Folder.go deleted file mode 100644 index cb762c0..0000000 --- a/generated-usage-examples/go/v2/19marchtestv2Folder.go +++ /dev/null @@ -1,3 +0,0 @@ -March 19 2025 - -This file lives in the v2 branch only. \ No newline at end of file diff --git a/usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh b/usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh deleted file mode 100644 index 9bfc0e2..0000000 --- a/usage-examples/go/atlas-sdk-go/.bluehawk/copy.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -# Copy project files to generated directory using Bluehawk -# Copied files are then pushed to Arch Center artifact repo via Copier App -set -euo pipefail - -# Set input and output directories -PROJECT=$(git rev-parse --show-toplevel) -INPUT_DIR="$PROJECT/usage-examples/go/atlas-sdk-go/" -OUTPUT_DIR="$PROJECT/generated-usage-examples/go/atlas-sdk-go/project-copy/" - -# Set directories and files to ignore -IGNORE=( - "README.md" - "bluehawk/" - "tests/" - ".*" - "*.gz" - "*.log" -) -IGNORE_ARGS=() -for path in "${IGNORE[@]}"; do - IGNORE_ARGS+=("--ignore=$path") -done - -# Set directories and files to rename -RENAME=( - "REPO_README.md:README.md" -) -RENAME_ARGS=() -for path in "${RENAME[@]}"; do - IFS=":" read -r src dst <<< "$path" # Split the path into source and destination - RENAME_ARGS+=("--rename=$src:$dst") # Add the rename argument to the array -done - -# Run Bluehawk copy command, passing all ignore args and "copy" state -.bluehawk copy \ - "${IGNORE_ARGS[@]}" \ - --state copy \ - -o "$OUTPUT_DIR" \ - "$INPUT_DIR" diff --git a/usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh b/usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh deleted file mode 100755 index e180edc..0000000 --- a/usage-examples/go/atlas-sdk-go/.bluehawk/snip.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -PROJECT=$(git rev-parse --show-toplevel) -GO_SDK_EXAMPLES="$PROJECT/usage-examples/go/atlas-sdk-go/" -GENERATED_EXAMPLES="$PROJECT/generated-usage-examples/go/atlas-sdk-go/usage-examples/" - -# ——— helper: run .bluehawk and only show the key lines ——— -run_snip() { - local extra_flags="$1" - local label="$2" - local dest="$GENERATED_EXAMPLES" - - echo "→ $label" - npx bluehawk snip "$GO_SDK_EXAMPLES" -o "$GENERATED_EXAMPLES" -} -# ——— 1) global snippets ——— -run_snip "" "Global snippets" - -# ——— 2) state‑specific snippets ——— -read -r -p "Do you have any state tags to enter? [y/N]: " resp -if [[ $resp =~ ^[Yy]$ ]]; then - read -r -a STATES -p "Enter one or more state tags (space‑separated): " - for s in "${STATES[@]}"; do - run_snip "--state $s" "State: $s" - done -else - echo "No state tags — skipping." -fi - -# ——— 3) copy non‑snippable files ——— -# list paths *relative* to $GO_SDK_EXAMPLES -readonly COPY_FILES=( - "configs/config.json" - # add any other JSON (or other) files here… - # DON'T COPY SOURCE README.md -) - -echo "→ Copying raw files (${#COPY_FILES[@]})" -for rel in "${COPY_FILES[@]}"; do - src="$GO_SDK_EXAMPLES/$rel" - dest_dir="$GENERATED_EXAMPLES/" - mkdir -p "$dest_dir" - base=$(basename "$rel") - cp "$src" "$dest_dir/snippet.$base" - echo " • $rel → snippet.$base" -done - -# ——— 4) cleanup ——— - find "$GENERATED_EXAMPLES/" -type f \ - -name '*.snippet.*-full-example.*' \ - -delete -print \ - | sed 's/^/ └ removed: /' - -find "$PROJECT" -name "*.gz" -delete diff --git a/usage-examples/go/atlas-sdk-go/REPO_README.md b/usage-examples/go/atlas-sdk-go/REPO_README.md index e761866..ce2bbb0 100644 --- a/usage-examples/go/atlas-sdk-go/REPO_README.md +++ b/usage-examples/go/atlas-sdk-go/REPO_README.md @@ -6,33 +6,6 @@ code examples that follow recommendations in MongoDB's official You can run, download, and modify these code examples as starting points for configuring your MongoDB Atlas architecture for your use case. -## Overview - -### Project Structure - -```text -Project Root -├── cmd -│ ├── get_logs/main.go -│ ├── get_metrics_disk/main.go -│ ├── get_metrics_process/main.go -├── internal -│ ├── auth -│ │ ├── auth.go -│ ├── logs -│ │ ├── downloader.go -│ ├── metrics -│ │ ├── metrics.go -├── go.mod -├── go.sum -├── configs -│ ├── config.json -├── .env # -``` - -> NOTE: In a production environment, you are likely to use - -note in the README that you'll most likely be using a secrets manager in prod ## License This project is licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). @@ -48,4 +21,4 @@ leaving a star rating. ## Contributing We are not currently accepting public contributions to this repository at this -time.**** +time. \ No newline at end of file diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 78c5a7d..0a99f2d 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -21,7 +21,7 @@ import ( func main() { _ = godotenv.Load() - secrets, cfg, err := config.LoadAll("configs/.config.json") + secrets, cfg, err := config.LoadAll("configs/config.json") if err != nil { log.Fatalf("config load: %v", err) } @@ -68,3 +68,5 @@ func main() { fmt.Println("Deleted generated files from", outDir) // :remove-end: } + +// :snippet-end: [get-logs] diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go index 766ec9c..6ff9be0 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go @@ -18,7 +18,7 @@ import ( func main() { _ = godotenv.Load() - secrets, cfg, err := config.LoadAll("configs/.config.json") + secrets, cfg, err := config.LoadAll("configs/config.json") if err != nil { log.Fatalf("config load: %v", err) } diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go index fa2ac29..c96c0e5 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go @@ -18,7 +18,7 @@ import ( func main() { _ = godotenv.Load() - secrets, cfg, err := config.LoadAll("configs/.config.json") + secrets, cfg, err := config.LoadAll("configs/config.json") if err != nil { log.Fatalf("config load: %v", err) } diff --git a/usage-examples/go/atlas-sdk-go/configs/.config.json b/usage-examples/go/atlas-sdk-go/configs/.config.json deleted file mode 100644 index e426705..0000000 --- a/usage-examples/go/atlas-sdk-go/configs/.config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "5bfda007553855125605a5cf", - "ATLAS_PROJECT_ID": "5f60207f14dfb25d23101102", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.nr3ko.mongodb.net:27017" -} diff --git a/usage-examples/go/atlas-sdk-go/internal/config/secrets.go b/usage-examples/go/atlas-sdk-go/internal/config/secrets.go index 1698dcf..16dbeb2 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config/secrets.go +++ b/usage-examples/go/atlas-sdk-go/internal/config/secrets.go @@ -7,19 +7,11 @@ import ( ) const ( - EnvMongoUser = "MONGODB_USER_NAME" - EnvMongoPassword = "MONGODB_PASSWORD" - EnvAtlasAPIKey = "MONGODB_ATLAS_PUBLIC_KEY" - EnvAtlasAPISecret = "MONGODB_ATLAS_PRIVATE_KEY" EnvSAClientID = "MONGODB_ATLAS_SERVICE_ACCOUNT_ID" EnvSAClientSecret = "MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET" ) type Secrets struct { - MongoDBUser string - MongoDBPassword string - AtlasAPIKey string - AtlasAPISecret string ServiceAccountID string ServiceAccountSecret string } @@ -36,10 +28,6 @@ func LoadSecrets() (*Secrets, error) { } } - look(EnvMongoUser, &s.MongoDBUser) - look(EnvMongoPassword, &s.MongoDBPassword) - look(EnvAtlasAPIKey, &s.AtlasAPIKey) - look(EnvAtlasAPISecret, &s.AtlasAPISecret) look(EnvSAClientID, &s.ServiceAccountID) look(EnvSAClientSecret, &s.ServiceAccountSecret) diff --git a/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh index c2b81c3..223f58f 100755 --- a/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh +++ b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh @@ -5,8 +5,6 @@ usage() { cat < [flags] -If you run with **no arguments**, you’ll be prompted interactively. - Commands: snip Extract code examples from Bluehawk snippets copy Copy sanitized project files @@ -28,7 +26,6 @@ IGNORE_PATTERNS=( "scripts/" "tests/" ".*" - "logs/" "*.gz" "*.log" ) @@ -45,26 +42,30 @@ if [[ $# -eq 0 ]]; then echo "enter 'snip' or 'copy'" done -STATE=$([[ "$CMD" == "snip" ]] && echo "" || echo "copy") -OUTPUT_DIR=$([[ "$CMD" == "snip" ]] && echo "$OUTPUT_DIR" || echo "$OUTPUT_DIR/project-copy") - + STATE=$([[ "$CMD" == "snip" ]] && echo "" || echo "copy") + OUTPUT_DIR=$([[ "$CMD" == "snip" ]] && echo "$OUTPUT_DIR" || echo "$OUTPUT_DIR/project-copy") -IGNORE_ARGS=() -for pattern in "${IGNORE_PATTERNS[@]}"; do - IGNORE_ARGS+=(--ignore="$pattern") -done + IGNORE_ARGS=() + for pattern in "${IGNORE_PATTERNS[@]}"; do + IGNORE_ARGS+=(--ignore="$pattern") + done -RENAME_ARGS=() + RENAME_ARGS=() if [[ "$CMD" != "snip" ]]; then for rule in "${RENAME_PATTERNS[@]}"; do RENAME_ARGS+=(--rename="$rule") done +else + RENAME_ARGS=() fi -# call .bluehawk with all the args -.bluehawk "$CMD" \ - --state="$STATE" \ - -o "$OUTPUT_DIR" \ - "${IGNORE_ARGS[@]}" \ - "${RENAME_ARGS[@]}" \ - "$INPUT_DIR" + # call bluehawk with all the args + bluehawk "$CMD" \ + --state="$STATE" \ + -o "$OUTPUT_DIR" \ + "${IGNORE_ARGS[@]}" \ + "${RENAME_ARGS[@]}" \ + "$INPUT_DIR" +else + usage +fi diff --git a/usage-examples/go/newgotestfile.go b/usage-examples/go/newgotestfile.go deleted file mode 100644 index 5879b07..0000000 --- a/usage-examples/go/newgotestfile.go +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "filename": "go/delete_me.go", - "repo": "", - "branch": "", - "deleted_on": "2025-03-07T21:53:21Z" - }, - { - "filename": "go/newgotestfile.go", - "repo": "docs-code-examples-test-target", - "branch": "v2.2", - "deleted_on": "2025-03-19T16:08:30-07:00" - } -] \ No newline at end of file diff --git a/usage-examples/go/ohhai_detete_me b/usage-examples/go/ohhai_detete_me deleted file mode 100644 index c0b264e..0000000 --- a/usage-examples/go/ohhai_detete_me +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "filename": "go/delete_me.go", - "repo": "", - "branch": "", - "deleted_on": "2025-03-07T21:53:21Z" - }, - { - "filename": "go/ohhai_detete_me", - "repo": "docs-code-examples-test-target", - "branch": "v2.2", - "deleted_on": "2025-03-19T16:08:31-07:00" - } -] \ No newline at end of file diff --git a/usage-examples/go/v22testfile2.go b/usage-examples/go/v22testfile2.go deleted file mode 100644 index 916f4ac..0000000 --- a/usage-examples/go/v22testfile2.go +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "filename": "go/delete_me.go", - "repo": "", - "branch": "", - "deleted_on": "2025-03-07T21:53:21Z" - }, - { - "filename": "go/v22testfile2.go", - "repo": "docs-code-examples-test-target", - "branch": "v2.2", - "deleted_on": "2025-03-19T16:08:33-07:00" - } -] \ No newline at end of file From cfdc15a58778f07c776c954df39c20fea9eb24ba Mon Sep 17 00:00:00 2001 From: cbullinger <115956901+cbullinger@users.noreply.github.com> Date: Wed, 7 May 2025 13:18:40 -0400 Subject: [PATCH 21/22] Update usage-examples/go/atlas-sdk-go/internal/utils.go Co-authored-by: Dachary --- usage-examples/go/atlas-sdk-go/internal/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usage-examples/go/atlas-sdk-go/internal/utils.go b/usage-examples/go/atlas-sdk-go/internal/utils.go index b1aff89..1f0d0ae 100644 --- a/usage-examples/go/atlas-sdk-go/internal/utils.go +++ b/usage-examples/go/atlas-sdk-go/internal/utils.go @@ -3,8 +3,8 @@ package internal import ( "io" "log" - "os" - "path/filepath" + "os" // :remove: + "path/filepath" // :remove: ) // SafeClose closes c and logs a warning on error. From eff647c5685093f0f99b35b617fd4ca2d9fac410 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Wed, 7 May 2025 16:32:00 -0400 Subject: [PATCH 22/22] Apply review feedback and rerun BH script --- .../go/atlas-sdk-go/main.snippet.get-logs.go | 15 +-- .../main.snippet.get-metrics-dev.go | 10 +- .../main.snippet.get-metrics-prod.go | 10 +- .../go/atlas-sdk-go/project-copy/.gitignore | 6 ++ .../project-copy/cmd/get_logs/main.go | 15 +-- .../project-copy/cmd/get_metrics_disk/main.go | 10 +- .../cmd/get_metrics_process/main.go | 10 +- .../go/atlas-sdk-go/project-copy/go.mod | 2 +- .../go/atlas-sdk-go/project-copy/go.sum | 6 +- .../project-copy/internal/auth/client.go | 3 +- .../internal/config/{loader.go => loadall.go} | 0 .../config/{json.go => loadconfig.go} | 5 +- .../config/{secrets.go => loadenv.go} | 0 .../project-copy/internal/logs/fetch_test.go | 83 --------------- .../project-copy/internal/logs/file.go | 5 +- .../project-copy/internal/logs/file_test.go | 33 ------ .../project-copy/internal/logs/gzip.go | 3 +- .../project-copy/internal/logs/gzip_test.go | 50 --------- .../project-copy/internal/metrics/disk.go | 7 +- .../internal/metrics/disk_test.go | 77 -------------- .../project-copy/internal/metrics/process.go | 7 +- .../internal/metrics/process_test.go | 91 ---------------- .../project-copy/internal/utils.go | 2 - usage-examples/go/atlas-sdk-go/.gitignore | 6 ++ .../go/atlas-sdk-go/INTERNAL_README.md | 90 ++++++++++++++++ usage-examples/go/atlas-sdk-go/README.md | 100 +++--------------- usage-examples/go/atlas-sdk-go/REPO_README.md | 24 ----- .../go/atlas-sdk-go/cmd/get_logs/main.go | 15 +-- .../atlas-sdk-go/cmd/get_metrics_disk/main.go | 10 +- .../cmd/get_metrics_process/main.go | 10 +- usage-examples/go/atlas-sdk-go/go.mod | 2 +- usage-examples/go/atlas-sdk-go/go.sum | 6 +- .../go/atlas-sdk-go/internal/auth/client.go | 3 +- .../internal/config/{loader.go => loadall.go} | 0 .../config/{json.go => loadconfig.go} | 5 +- .../config/{secrets.go => loadenv.go} | 0 .../atlas-sdk-go/internal/logs/fetch_test.go | 3 +- .../go/atlas-sdk-go/internal/logs/file.go | 5 +- .../go/atlas-sdk-go/internal/logs/gzip.go | 3 +- .../go/atlas-sdk-go/internal/metrics/disk.go | 7 +- .../internal/metrics/disk_test.go | 3 +- .../atlas-sdk-go/internal/metrics/process.go | 7 +- .../internal/metrics/process_test.go | 5 +- .../go/atlas-sdk-go/internal/utils.go | 2 +- .../go/atlas-sdk-go/scripts/bluehawk.sh | 25 +++-- 45 files changed, 227 insertions(+), 554 deletions(-) create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/.gitignore rename generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/{loader.go => loadall.go} (100%) rename generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/{json.go => loadconfig.go} (97%) rename generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/{secrets.go => loadenv.go} (100%) delete mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go delete mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go create mode 100644 usage-examples/go/atlas-sdk-go/.gitignore create mode 100644 usage-examples/go/atlas-sdk-go/INTERNAL_README.md delete mode 100644 usage-examples/go/atlas-sdk-go/REPO_README.md rename usage-examples/go/atlas-sdk-go/internal/config/{loader.go => loadall.go} (100%) rename usage-examples/go/atlas-sdk-go/internal/config/{json.go => loadconfig.go} (97%) rename usage-examples/go/atlas-sdk-go/internal/config/{secrets.go => loadenv.go} (100%) diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go index 8864477..6c9acd3 100644 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-logs.go @@ -2,18 +2,20 @@ package main import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/logs" "context" "fmt" - "github.com/joho/godotenv" - "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" "os" "path/filepath" "time" + + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" ) func main() { @@ -56,6 +58,5 @@ func main() { log.Fatalf("decompress: %v", err) } fmt.Println("Uncompressed log to", txtPath) - } diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go index 1d32483..8f96696 100644 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-dev.go @@ -2,15 +2,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go index 3fd1d51..62c8dd4 100644 --- a/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go +++ b/generated-usage-examples/go/atlas-sdk-go/main.snippet.get-metrics-prod.go @@ -2,15 +2,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/.gitignore b/generated-usage-examples/go/atlas-sdk-go/project-copy/.gitignore new file mode 100644 index 0000000..22cadb7 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/.gitignore @@ -0,0 +1,6 @@ +# Secrets +.env + +# Logs +*.log +*.gz diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go index 6b62aa0..99ec158 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.go @@ -1,18 +1,20 @@ package main import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/logs" "context" "fmt" - "github.com/joho/godotenv" - "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" "os" "path/filepath" "time" + + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" ) func main() { @@ -55,6 +57,5 @@ func main() { log.Fatalf("decompress: %v", err) } fmt.Println("Uncompressed log to", txtPath) - } diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go index b508bf8..912cc75 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.go @@ -1,15 +1,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go index ffbf432..26fb4a3 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.go @@ -1,15 +1,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod index f26b6af..29ef1b0 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod @@ -13,6 +13,6 @@ require ( github.com/mongodb-forks/digest v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum index 01a0f83..20ec82d 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum @@ -1,7 +1,5 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKksrOoc= @@ -14,8 +12,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go index eb28c0d..7e8f192 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/client.go @@ -1,10 +1,11 @@ package auth import ( - "atlas-sdk-go/internal/config" "context" "fmt" + "atlas-sdk-go/internal/config" + "go.mongodb.org/atlas-sdk/v20250219001/admin" ) diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadall.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loader.go rename to generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadall.go diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadconfig.go similarity index 97% rename from generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go rename to generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadconfig.go index d89bffd..e55cd57 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/json.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadconfig.go @@ -1,11 +1,12 @@ package config import ( - "atlas-sdk-go/internal" "encoding/json" "fmt" "os" "strings" + + "atlas-sdk-go/internal" ) type Config struct { @@ -29,7 +30,6 @@ func LoadConfig(path string) (*Config, error) { return nil, fmt.Errorf("decode %s: %w", path, err) } - // defaults if c.BaseURL == "" { c.BaseURL = "https://cloud.mongodb.com" } @@ -40,7 +40,6 @@ func LoadConfig(path string) (*Config, error) { } } - // required if c.OrgID == "" || c.ProjectID == "" { return nil, fmt.Errorf("ATLAS_ORG_ID and ATLAS_PROJECT_ID are required") } diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadenv.go similarity index 100% rename from generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/secrets.go rename to generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config/loadenv.go diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go deleted file mode 100644 index b1c93b7..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/fetch_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package logs - -import ( - "atlas-sdk-go/internal" - "context" - "fmt" - "io" - "strings" - "testing" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" -) - -func TestFetchHostLogs_Unit(t *testing.T) { - t.Parallel() - ctx := context.Background() - - // common params - params := &admin.GetHostLogsApiParams{ - GroupId: "gID", - HostName: "hName", - LogName: "mongodb", - } - - cases := []struct { - name string - setup func(m *mockadmin.MonitoringAndLogsApi) - wantErr bool - wantBody string - }{ - { - name: "API error", - wantErr: true, - setup: func(m *mockadmin.MonitoringAndLogsApi) { - m.EXPECT(). - GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). - Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() - m.EXPECT(). - GetHostLogsExecute(mock.Anything). - Return(nil, nil, fmt.Errorf("API error")).Once() - }, - }, - { - name: "Successful response", - wantErr: false, - wantBody: "log-data", - setup: func(m *mockadmin.MonitoringAndLogsApi) { - m.EXPECT(). - GetHostLogs(mock.Anything, params.GroupId, params.HostName, params.LogName). - Return(admin.GetHostLogsApiRequest{ApiService: m}).Once() - m.EXPECT(). - GetHostLogsExecute(mock.Anything). - Return(io.NopCloser(strings.NewReader("log-data")), nil, nil).Once() - }, - }, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - mockSvc := mockadmin.NewMonitoringAndLogsApi(t) - tc.setup(mockSvc) - - rc, err := FetchHostLogs(ctx, mockSvc, params) - if tc.wantErr { - require.ErrorContainsf(t, err, "failed to fetch logs", "expected API error") - require.Nil(t, rc) - return - } - - require.NoError(t, err) - defer internal.SafeClose(rc) - - data, err := io.ReadAll(rc) - require.NoError(t, err) - require.Equal(t, tc.wantBody, string(data)) - }) - } -} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go index dfed136..b68f17f 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file.go @@ -1,14 +1,15 @@ package logs import ( - "atlas-sdk-go/internal" "fmt" "io" "os" + + "atlas-sdk-go/internal" ) // WriteToFile copies everything from r into a new file at path. -// It will create (or truncate) that file. +// It will create or truncate that file. func WriteToFile(r io.Reader, path string) error { f, err := os.Create(path) if err != nil { diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go deleted file mode 100644 index 8876d5a..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/file_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package logs - -import ( - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestWriteToFile_Success(t *testing.T) { - // create a temp dir and file - tmp := t.TempDir() - path := filepath.Join(tmp, "out.txt") - - input := "hello world" - r := strings.NewReader(input) - - require.NoError(t, WriteToFile(r, path)) - - // verify file exists and content matches - data, err := os.ReadFile(path) - require.NoError(t, err) - require.Equal(t, input, string(data)) -} - -func TestWriteToFile_Error(t *testing.T) { - path := "does-not-exist/out.txt" - err := WriteToFile(strings.NewReader("x"), path) - require.Error(t, err) - require.Contains(t, err.Error(), "create") -} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go index 8505f93..13901f6 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip.go @@ -1,10 +1,11 @@ package logs import ( - "atlas-sdk-go/internal" "compress/gzip" "fmt" "os" + + "atlas-sdk-go/internal" ) // DecompressGzip opens a .gz file and unpacks to specified destination. diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go deleted file mode 100644 index 9cbee64..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/logs/gzip_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package logs - -import ( - "compress/gzip" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestDecompressGzip_Success(t *testing.T) { - // create a temp dir and file - tmp := t.TempDir() - src := filepath.Join(tmp, "test.gz") - dst := filepath.Join(tmp, "test.txt") - - // create a gzip file and write some data to it - f, err := os.Create(src) - require.NoError(t, err) - - gz := gzip.NewWriter(f) - _, err = gz.Write([]byte("foobar")) - require.NoError(t, err) - require.NoError(t, gz.Close()) - require.NoError(t, f.Close()) - - // call the function to test - require.NoError(t, DecompressGzip(src, dst)) - - // verify the output - data, err := os.ReadFile(dst) - require.NoError(t, err) - require.Equal(t, "foobar", string(data)) -} - -func TestDecompressGzip_SourceNotFound(t *testing.T) { - tmp := t.TempDir() - src := filepath.Join(tmp, "nofile.gz") - dst := filepath.Join(tmp, "out.txt") - - // source file does not exist - err := DecompressGzip(src, dst) - require.Error(t, err) - require.Contains(t, err.Error(), "open") - - // destination file does not exist - _, err2 := os.Stat(dst) - require.True(t, os.IsNotExist(err2)) -} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go index cd9d597..e5b1636 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk.go @@ -8,12 +8,7 @@ import ( ) // FetchDiskMetrics returns measurements for a specified disk partition -func FetchDiskMetrics( - ctx context.Context, - sdk admin.MonitoringAndLogsApi, - p *admin.GetDiskMeasurementsApiParams, -) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - +func FetchDiskMetrics(ctx context.Context, sdk admin.MonitoringAndLogsApi, p *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { req := sdk.GetDiskMeasurements(ctx, p.GroupId, p.PartitionName, p.ProcessId) req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go deleted file mode 100644 index 66d425f..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/disk_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package metrics - -import ( - "context" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" - "testing" -) - -// ----------------------------------------------------------------------------- -// Integration tests against test HTTP server -// ----------------------------------------------------------------------------- -// TODO: Implement integration tests - -// ----------------------------------------------------------------------------- -// Unit‐level tests against SDK mocks -// ----------------------------------------------------------------------------- - -func TestFetchDiskMetrics(t *testing.T) { - t.Parallel() - ctx := context.Background() - - cases := []struct { - name string - view *admin.ApiMeasurementsGeneralViewAtlas - wantErr bool - wantCount int - }{ - {name: "Happy path returns data", - view: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{{ - Name: admin.PtrString("DISK_METRIC"), - DataPoints: &[]admin.MetricDataPointAtlas{{ - Timestamp: admin.PtrTime(parseTS(t, fixedTS)), - Value: admin.PtrFloat32(4.56)}}}}}, - wantCount: 1}, - {name: "No available data returns error", - view: &admin.ApiMeasurementsGeneralViewAtlas{}, - wantErr: true}, - } - - baseDisk := admin.GetDiskMeasurementsApiParams{ - GroupId: "gID", - PartitionName: "part", - ProcessId: "pID", - Granularity: admin.PtrString("P1D"), - Period: admin.PtrString("P1D"), - M: &[]string{"DISK_METRIC"}, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - // setup mock SDK - mockSvc := mockadmin.NewMonitoringAndLogsApi(t) - mockSvc.EXPECT(). - GetDiskMeasurements(mock.Anything, baseDisk.GroupId, baseDisk.PartitionName, baseDisk.ProcessId). - Return(admin.GetDiskMeasurementsApiRequest{ApiService: mockSvc}).Once() - mockSvc.EXPECT(). - GetDiskMeasurementsExecute(mock.Anything). - Return(tc.view, nil, nil).Once() - - result, err := FetchDiskMetrics(ctx, mockSvc, &baseDisk) - - if tc.wantErr { - require.Error(t, err) - return - } - require.NoError(t, err) - require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) - require.Len(t, *result.Measurements, tc.wantCount) - }) - } -} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go index 53819b7..c250f72 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process.go @@ -8,12 +8,7 @@ import ( ) // FetchProcessMetrics returns measurements for a specified host process -func FetchProcessMetrics( - ctx context.Context, - sdk admin.MonitoringAndLogsApi, - p *admin.GetHostMeasurementsApiParams, -) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - +func FetchProcessMetrics(ctx context.Context, sdk admin.MonitoringAndLogsApi, p *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { req := sdk.GetHostMeasurements(ctx, p.GroupId, p.ProcessId) req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go deleted file mode 100644 index 52da64f..0000000 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/metrics/process_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package metrics - -import ( - "context" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "go.mongodb.org/atlas-sdk/v20250219001/admin" - "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" - "testing" - "time" -) - -// fixed timestamp for tests -var fixedTS = "2025-01-01T12:00:00Z" - -// parseTS wraps time.Parse and flags error on test failure -func parseTS(t *testing.T, ts string) time.Time { - t.Helper() - parsed, err := time.Parse(time.RFC3339, ts) - require.NoError(t, err) - return parsed -} - -// ----------------------------------------------------------------------------- -// Integration tests against test HTTP server -// ----------------------------------------------------------------------------- -// TODO: Implement integration tests - -// ----------------------------------------------------------------------------- -// Unit‐level tests against SDK mocks -// ----------------------------------------------------------------------------- - -func TestFetchProcessMetrics_Unit(t *testing.T) { - t.Parallel() - ctx := context.Background() - - cases := []struct { - name string - view *admin.ApiMeasurementsGeneralViewAtlas - wantErr bool - wantCount int - }{ - { - name: "Happy path returns data", - view: &admin.ApiMeasurementsGeneralViewAtlas{ - Measurements: &[]admin.MetricsMeasurementAtlas{{ - Name: admin.PtrString("PROCESS_METRIC"), - DataPoints: &[]admin.MetricDataPointAtlas{{ - Timestamp: admin.PtrTime(parseTS(t, fixedTS)), - Value: admin.PtrFloat32(1.23)}}}}}, - wantCount: 1, - }, - { - name: "No available data returns error", - view: &admin.ApiMeasurementsGeneralViewAtlas{}, - wantErr: true, - }, - } - - var baseProcess = admin.GetHostMeasurementsApiParams{ - GroupId: "gID", - ProcessId: "pID", - Granularity: admin.PtrString("PT1H"), - Period: admin.PtrString("P1D"), - M: &[]string{"METRIC"}, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - mockSvc := mockadmin.NewMonitoringAndLogsApi(t) - mockSvc.EXPECT(). - GetHostMeasurements(mock.Anything, baseProcess.GroupId, baseProcess.ProcessId). - Return(admin.GetHostMeasurementsApiRequest{ApiService: mockSvc}).Once() - mockSvc.EXPECT(). - GetHostMeasurementsExecute(mock.Anything). - Return(tc.view, nil, nil).Once() - - result, err := FetchProcessMetrics(ctx, mockSvc, &baseProcess) - - if tc.wantErr { - require.Error(t, err) - return - } - require.NoError(t, err) - require.ElementsMatch(t, *result.Measurements, tc.view.GetMeasurements()) - require.Len(t, *result.Measurements, tc.wantCount) - }) - } -} diff --git a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go index 7104dec..f105de6 100644 --- a/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/utils.go @@ -3,8 +3,6 @@ package internal import ( "io" "log" - "os" - "path/filepath" ) // SafeClose closes c and logs a warning on error. diff --git a/usage-examples/go/atlas-sdk-go/.gitignore b/usage-examples/go/atlas-sdk-go/.gitignore new file mode 100644 index 0000000..22cadb7 --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/.gitignore @@ -0,0 +1,6 @@ +# Secrets +.env + +# Logs +*.log +*.gz diff --git a/usage-examples/go/atlas-sdk-go/INTERNAL_README.md b/usage-examples/go/atlas-sdk-go/INTERNAL_README.md new file mode 100644 index 0000000..be9cd5d --- /dev/null +++ b/usage-examples/go/atlas-sdk-go/INTERNAL_README.md @@ -0,0 +1,90 @@ +# Atlas SDK for Go + +This project demonstrates how to script specific functionality using the Atlas +SDK for Go. Code examples are used in the Atlas Architecture Center docs, and +the project is made available in a user-facing repo. + +## Project Structure +```text +atlas-sdk-go/ +│── cmd/ # Self-contained, runnable scripts +│ ├── get_logs/ +│ ├── main.go +│ ├── get_metrics_disk/ +│ ├── main.go +│ ├── get_metrics_process/ +│ ├── main.go +│── config/ # Atlas configuration settings +│ ├── config.json +│── internal/ # Shared internal logic +│ ├── auth/ +| ├── client.go +│ ├── config/ +| ├── json.go +| ├── secrets.go +| ├── loader.go +│── .env # Secrets file (excluded from Git) +│── go.mod +│── go.sum +│── README.md # Internal-only README (do not copy with Copier Tool) +│── scripts/ # Internal-only Bluehawk scripts to snip and copy code examples +│ ├── bluehawk.sh +``` + +## Runnable Scripts +You can run individual scripts from the terminal. For example, to run `get_logs/main.go`: +```shell +go run cmd/get_logs/main.go +``` + +## Set up + +### Prerequisites + +- A [service account](https://www.mongodb.com/docs/atlas/api/service-accounts-overview/#std-label-service-accounts-overview) with access to your Atlas project + +> **NOTE:** Some scripts require an M10+ cluster + +### Set environment variables and config file + +1. Set the following variable values, either as a `.env` file in the root directory or through your IDE: + ```shell + MONGODB_ATLAS_SERVICE_ACCOUNT_ID=your-service-account-id + MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET=your-service-account-secret + ``` +2. Update the placeholders in the `configs/config.json` file with your Atlas cluster information: + ```json + { + + "ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "Cluster0", + "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" + + } + ``` + > **NOTE: Group ID == Project ID** Groups and projects are synonymous terms. Groups and projects are synonymous terms. Your group id is the same as your project id. + +## Write Tests + +# TODO + +## Generate Examples + +This project uses Bluehawk to generate code examples from the source code. + +- Usage examples for the docs. These are generated using the `bluehawk snip` + command based on the `snippet` markup in the code file. +- Full project files for the user-facing project repo. These are generated using + the `bluehawk copy` command. + +Run the bluehawk script and enter either `snip` or `copy`. The selected command +runs with the defined defaults. + + ```shell + ./scripts/bluehawk.sh + ``` + +> **NOTE: "Copy" State** This project uses a state named "copy" specifically for any manipulations needed for code copied to the artifact repo. + diff --git a/usage-examples/go/atlas-sdk-go/README.md b/usage-examples/go/atlas-sdk-go/README.md index be9cd5d..ce2bbb0 100644 --- a/usage-examples/go/atlas-sdk-go/README.md +++ b/usage-examples/go/atlas-sdk-go/README.md @@ -1,90 +1,24 @@ -# Atlas SDK for Go +# MongoDB Atlas Architecture Center Go SDK Code Examples -This project demonstrates how to script specific functionality using the Atlas -SDK for Go. Code examples are used in the Atlas Architecture Center docs, and -the project is made available in a user-facing repo. +This repository contains [Atlas Go SDK](https://www.mongodb.com/docs/atlas/sdk/) +code examples that follow recommendations in MongoDB's official +[Atlas Architecture Center documentation](https://www.mongodb.com/docs/atlas/architecture/current/). +You can run, download, and modify these code examples as starting points for +configuring your MongoDB Atlas architecture for your use case. -## Project Structure -```text -atlas-sdk-go/ -│── cmd/ # Self-contained, runnable scripts -│ ├── get_logs/ -│ ├── main.go -│ ├── get_metrics_disk/ -│ ├── main.go -│ ├── get_metrics_process/ -│ ├── main.go -│── config/ # Atlas configuration settings -│ ├── config.json -│── internal/ # Shared internal logic -│ ├── auth/ -| ├── client.go -│ ├── config/ -| ├── json.go -| ├── secrets.go -| ├── loader.go -│── .env # Secrets file (excluded from Git) -│── go.mod -│── go.sum -│── README.md # Internal-only README (do not copy with Copier Tool) -│── scripts/ # Internal-only Bluehawk scripts to snip and copy code examples -│ ├── bluehawk.sh -``` +## License -## Runnable Scripts -You can run individual scripts from the terminal. For example, to run `get_logs/main.go`: -```shell -go run cmd/get_logs/main.go -``` +This project is licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). -## Set up +## Issues -### Prerequisites +To report an issue with any of these code examples, please leave feedback +through the corresponding documentation page in the +[MongoDB Atlas Architecture Center](https://www.mongodb.com/docs/atlas/architecture/current/). +Using the `Rate This Page` button, you can add a comment about the issue after +leaving a star rating. -- A [service account](https://www.mongodb.com/docs/atlas/api/service-accounts-overview/#std-label-service-accounts-overview) with access to your Atlas project - -> **NOTE:** Some scripts require an M10+ cluster - -### Set environment variables and config file - -1. Set the following variable values, either as a `.env` file in the root directory or through your IDE: - ```shell - MONGODB_ATLAS_SERVICE_ACCOUNT_ID=your-service-account-id - MONGODB_ATLAS_SERVICE_ACCOUNT_SECRET=your-service-account-secret - ``` -2. Update the placeholders in the `configs/config.json` file with your Atlas cluster information: - ```json - { - - "ATLAS_BASE_URL": "https://cloud.mongodb.com", - "ATLAS_ORG_ID": "", - "ATLAS_PROJECT_ID": "", - "ATLAS_CLUSTER_NAME": "Cluster0", - "ATLAS_PROCESS_ID": "cluster0-shard-00-00.ab1cd.mongodb.net:27017" - - } - ``` - > **NOTE: Group ID == Project ID** Groups and projects are synonymous terms. Groups and projects are synonymous terms. Your group id is the same as your project id. - -## Write Tests - -# TODO - -## Generate Examples - -This project uses Bluehawk to generate code examples from the source code. - -- Usage examples for the docs. These are generated using the `bluehawk snip` - command based on the `snippet` markup in the code file. -- Full project files for the user-facing project repo. These are generated using - the `bluehawk copy` command. - -Run the bluehawk script and enter either `snip` or `copy`. The selected command -runs with the defined defaults. - - ```shell - ./scripts/bluehawk.sh - ``` - -> **NOTE: "Copy" State** This project uses a state named "copy" specifically for any manipulations needed for code copied to the artifact repo. +## Contributing +We are not currently accepting public contributions to this repository at this +time. \ No newline at end of file diff --git a/usage-examples/go/atlas-sdk-go/REPO_README.md b/usage-examples/go/atlas-sdk-go/REPO_README.md deleted file mode 100644 index ce2bbb0..0000000 --- a/usage-examples/go/atlas-sdk-go/REPO_README.md +++ /dev/null @@ -1,24 +0,0 @@ -# MongoDB Atlas Architecture Center Go SDK Code Examples - -This repository contains [Atlas Go SDK](https://www.mongodb.com/docs/atlas/sdk/) -code examples that follow recommendations in MongoDB's official -[Atlas Architecture Center documentation](https://www.mongodb.com/docs/atlas/architecture/current/). -You can run, download, and modify these code examples as starting points for -configuring your MongoDB Atlas architecture for your use case. - -## License - -This project is licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). - -## Issues - -To report an issue with any of these code examples, please leave feedback -through the corresponding documentation page in the -[MongoDB Atlas Architecture Center](https://www.mongodb.com/docs/atlas/architecture/current/). -Using the `Rate This Page` button, you can add a comment about the issue after -leaving a star rating. - -## Contributing - -We are not currently accepting public contributions to this repository at this -time. \ No newline at end of file diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go index 0a99f2d..bf3f84b 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_logs/main.go @@ -5,18 +5,20 @@ package main import ( - "atlas-sdk-go/internal" - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/logs" "context" "fmt" - "github.com/joho/godotenv" - "go.mongodb.org/atlas-sdk/v20250219001/admin" "log" "os" "path/filepath" "time" + + "github.com/joho/godotenv" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + + "atlas-sdk-go/internal" + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/logs" ) func main() { @@ -59,7 +61,6 @@ func main() { log.Fatalf("decompress: %v", err) } fmt.Println("Uncompressed log to", txtPath) - // :remove-start: // NOTE Internal function to clean up any downloaded files if err := internal.SafeDelete(outDir); err != nil { diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go index 6ff9be0..2520d47 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_disk/main.go @@ -5,15 +5,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go index c96c0e5..db707c4 100644 --- a/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go +++ b/usage-examples/go/atlas-sdk-go/cmd/get_metrics_process/main.go @@ -5,15 +5,17 @@ package main import ( - "atlas-sdk-go/internal/auth" - "atlas-sdk-go/internal/config" - "atlas-sdk-go/internal/metrics" "context" "encoding/json" "fmt" + "log" + "github.com/joho/godotenv" "go.mongodb.org/atlas-sdk/v20250219001/admin" - "log" + + "atlas-sdk-go/internal/auth" + "atlas-sdk-go/internal/config" + "atlas-sdk-go/internal/metrics" ) func main() { diff --git a/usage-examples/go/atlas-sdk-go/go.mod b/usage-examples/go/atlas-sdk-go/go.mod index f26b6af..29ef1b0 100644 --- a/usage-examples/go/atlas-sdk-go/go.mod +++ b/usage-examples/go/atlas-sdk-go/go.mod @@ -13,6 +13,6 @@ require ( github.com/mongodb-forks/digest v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/usage-examples/go/atlas-sdk-go/go.sum b/usage-examples/go/atlas-sdk-go/go.sum index 01a0f83..20ec82d 100644 --- a/usage-examples/go/atlas-sdk-go/go.sum +++ b/usage-examples/go/atlas-sdk-go/go.sum @@ -1,7 +1,5 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/mongodb-forks/digest v1.1.0 h1:7eUdsR1BtqLv0mdNm4OXs6ddWvR4X2/OsLwdKksrOoc= @@ -14,8 +12,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0 h1:tm7d3xvbNFIpuvFcppXc1zdpM/dO7HwivpA+Y4np3uQ= go.mongodb.org/atlas-sdk/v20250219001 v20250219001.1.0/go.mod h1:huR1gWJhExa60NIRhsLDdc7RmmqKJJwnbdlA1UUh8V4= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/usage-examples/go/atlas-sdk-go/internal/auth/client.go b/usage-examples/go/atlas-sdk-go/internal/auth/client.go index eb28c0d..7e8f192 100644 --- a/usage-examples/go/atlas-sdk-go/internal/auth/client.go +++ b/usage-examples/go/atlas-sdk-go/internal/auth/client.go @@ -1,10 +1,11 @@ package auth import ( - "atlas-sdk-go/internal/config" "context" "fmt" + "atlas-sdk-go/internal/config" + "go.mongodb.org/atlas-sdk/v20250219001/admin" ) diff --git a/usage-examples/go/atlas-sdk-go/internal/config/loader.go b/usage-examples/go/atlas-sdk-go/internal/config/loadall.go similarity index 100% rename from usage-examples/go/atlas-sdk-go/internal/config/loader.go rename to usage-examples/go/atlas-sdk-go/internal/config/loadall.go diff --git a/usage-examples/go/atlas-sdk-go/internal/config/json.go b/usage-examples/go/atlas-sdk-go/internal/config/loadconfig.go similarity index 97% rename from usage-examples/go/atlas-sdk-go/internal/config/json.go rename to usage-examples/go/atlas-sdk-go/internal/config/loadconfig.go index d89bffd..e55cd57 100644 --- a/usage-examples/go/atlas-sdk-go/internal/config/json.go +++ b/usage-examples/go/atlas-sdk-go/internal/config/loadconfig.go @@ -1,11 +1,12 @@ package config import ( - "atlas-sdk-go/internal" "encoding/json" "fmt" "os" "strings" + + "atlas-sdk-go/internal" ) type Config struct { @@ -29,7 +30,6 @@ func LoadConfig(path string) (*Config, error) { return nil, fmt.Errorf("decode %s: %w", path, err) } - // defaults if c.BaseURL == "" { c.BaseURL = "https://cloud.mongodb.com" } @@ -40,7 +40,6 @@ func LoadConfig(path string) (*Config, error) { } } - // required if c.OrgID == "" || c.ProjectID == "" { return nil, fmt.Errorf("ATLAS_ORG_ID and ATLAS_PROJECT_ID are required") } diff --git a/usage-examples/go/atlas-sdk-go/internal/config/secrets.go b/usage-examples/go/atlas-sdk-go/internal/config/loadenv.go similarity index 100% rename from usage-examples/go/atlas-sdk-go/internal/config/secrets.go rename to usage-examples/go/atlas-sdk-go/internal/config/loadenv.go diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go b/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go index b1c93b7..9afef96 100644 --- a/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go +++ b/usage-examples/go/atlas-sdk-go/internal/logs/fetch_test.go @@ -1,13 +1,14 @@ package logs import ( - "atlas-sdk-go/internal" "context" "fmt" "io" "strings" "testing" + "atlas-sdk-go/internal" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.mongodb.org/atlas-sdk/v20250219001/admin" diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/file.go b/usage-examples/go/atlas-sdk-go/internal/logs/file.go index dfed136..b68f17f 100644 --- a/usage-examples/go/atlas-sdk-go/internal/logs/file.go +++ b/usage-examples/go/atlas-sdk-go/internal/logs/file.go @@ -1,14 +1,15 @@ package logs import ( - "atlas-sdk-go/internal" "fmt" "io" "os" + + "atlas-sdk-go/internal" ) // WriteToFile copies everything from r into a new file at path. -// It will create (or truncate) that file. +// It will create or truncate that file. func WriteToFile(r io.Reader, path string) error { f, err := os.Create(path) if err != nil { diff --git a/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go b/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go index 8505f93..13901f6 100644 --- a/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go +++ b/usage-examples/go/atlas-sdk-go/internal/logs/gzip.go @@ -1,10 +1,11 @@ package logs import ( - "atlas-sdk-go/internal" "compress/gzip" "fmt" "os" + + "atlas-sdk-go/internal" ) // DecompressGzip opens a .gz file and unpacks to specified destination. diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go b/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go index cd9d597..e5b1636 100644 --- a/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/disk.go @@ -8,12 +8,7 @@ import ( ) // FetchDiskMetrics returns measurements for a specified disk partition -func FetchDiskMetrics( - ctx context.Context, - sdk admin.MonitoringAndLogsApi, - p *admin.GetDiskMeasurementsApiParams, -) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - +func FetchDiskMetrics(ctx context.Context, sdk admin.MonitoringAndLogsApi, p *admin.GetDiskMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { req := sdk.GetDiskMeasurements(ctx, p.GroupId, p.PartitionName, p.ProcessId) req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go b/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go index 66d425f..f89fc5f 100644 --- a/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/disk_test.go @@ -2,11 +2,12 @@ package metrics import ( "context" + "testing" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.mongodb.org/atlas-sdk/v20250219001/admin" "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" - "testing" ) // ----------------------------------------------------------------------------- diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/process.go b/usage-examples/go/atlas-sdk-go/internal/metrics/process.go index 53819b7..c250f72 100644 --- a/usage-examples/go/atlas-sdk-go/internal/metrics/process.go +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/process.go @@ -8,12 +8,7 @@ import ( ) // FetchProcessMetrics returns measurements for a specified host process -func FetchProcessMetrics( - ctx context.Context, - sdk admin.MonitoringAndLogsApi, - p *admin.GetHostMeasurementsApiParams, -) (*admin.ApiMeasurementsGeneralViewAtlas, error) { - +func FetchProcessMetrics(ctx context.Context, sdk admin.MonitoringAndLogsApi, p *admin.GetHostMeasurementsApiParams) (*admin.ApiMeasurementsGeneralViewAtlas, error) { req := sdk.GetHostMeasurements(ctx, p.GroupId, p.ProcessId) req = req.Granularity(*p.Granularity).Period(*p.Period).M(*p.M) diff --git a/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go b/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go index 52da64f..bca7b79 100644 --- a/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go +++ b/usage-examples/go/atlas-sdk-go/internal/metrics/process_test.go @@ -2,12 +2,13 @@ package metrics import ( "context" + "testing" + "time" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.mongodb.org/atlas-sdk/v20250219001/admin" "go.mongodb.org/atlas-sdk/v20250219001/mockadmin" - "testing" - "time" ) // fixed timestamp for tests diff --git a/usage-examples/go/atlas-sdk-go/internal/utils.go b/usage-examples/go/atlas-sdk-go/internal/utils.go index 1f0d0ae..bca14f0 100644 --- a/usage-examples/go/atlas-sdk-go/internal/utils.go +++ b/usage-examples/go/atlas-sdk-go/internal/utils.go @@ -3,7 +3,7 @@ package internal import ( "io" "log" - "os" // :remove: + "os" // :remove: "path/filepath" // :remove: ) diff --git a/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh index 223f58f..049a5ad 100755 --- a/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh +++ b/usage-examples/go/atlas-sdk-go/scripts/bluehawk.sh @@ -22,14 +22,14 @@ INPUT_DIR="$PROJECT/usage-examples/go/atlas-sdk-go" OUTPUT_DIR="$PROJECT/generated-usage-examples/go/atlas-sdk-go/" STATE="" IGNORE_PATTERNS=( - "README.md" + "internal_*.*" "scripts/" - "tests/" - ".*" + "*_test.go" + ".env" "*.gz" "*.log" + "./logs" ) -RENAME_PATTERNS=('{"REPO_README.md":"README.md"}') # ─── Interactive mode ──────────────────────────────────────────────────────── if [[ $# -eq 0 ]]; then @@ -50,21 +50,20 @@ if [[ $# -eq 0 ]]; then IGNORE_ARGS+=(--ignore="$pattern") done - RENAME_ARGS=() -if [[ "$CMD" != "snip" ]]; then - for rule in "${RENAME_PATTERNS[@]}"; do - RENAME_ARGS+=(--rename="$rule") - done -else - RENAME_ARGS=() -fi +# RENAME_ARGS=() +#if [[ "$CMD" != "snip" ]]; then +# for rule in "${RENAME_PATTERNS[@]}"; do +# RENAME_ARGS+=(--rename="$rule") +# done +#else +# RENAME_ARGS=() +#fi # call bluehawk with all the args bluehawk "$CMD" \ --state="$STATE" \ -o "$OUTPUT_DIR" \ "${IGNORE_ARGS[@]}" \ - "${RENAME_ARGS[@]}" \ "$INPUT_DIR" else usage