From 10dd53cec7b187b824b817b6562b0d9ccdc65f54 Mon Sep 17 00:00:00 2001 From: cbullinger Date: Mon, 21 Apr 2025 07:48:41 -0400 Subject: [PATCH] Add project files copied with Bluehawk script --- config.json | 23 ++-- .../project-copy/cmd/get_logs/main.go | 110 ++++++++++++++++++ .../project-copy/cmd/get_metrics_disk/main.go | 63 ++++++++++ .../cmd/get_metrics_process/main.go | 66 +++++++++++ .../project-copy/configs/config.json | 7 ++ .../go/atlas-sdk-go/project-copy/go.mod | 17 +++ .../go/atlas-sdk-go/project-copy/go.sum | 20 ++++ .../project-copy/internal/auth/auth.go | 43 +++++++ .../project-copy/internal/config_loader.go | 56 +++++++++ .../project-copy/internal/secrets_loader.go | 33 ++++++ 10 files changed, 430 insertions(+), 8 deletions(-) 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 create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/configs/config.json create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/go.mod create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum create mode 100644 generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/auth.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/secrets_loader.go diff --git a/config.json b/config.json index cd3d0f1..23672be 100644 --- a/config.json +++ b/config.json @@ -1,16 +1,23 @@ [ { - "notes": "This is a test config. It can be safely deleted.", - "source_directory" : "generated-examples/go", - "target_repo" : "docs-code-examples-test-target", + "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/project-copy", + "target_repo" : "atlas-architecture-go-sdk", + "target_branch" : "copy-test", + "target_directory" : "." + }, + { + "notes": "Example config for copying files from a directory to another repo", + "source_directory" : "generated-examples", + "target_repo" : "my-target-repo-name", "target_branch" : "main", - "target_directory" : "go" + "target_directory" : "examples" }, { - "notes":"This is a test config that copies fake v2 code examples to the v2.2 driver branch.", - "source_directory" : "generated-examples/go/v2", - "target_repo" : "docs-code-examples-test-target", + "notes":"Example config for copying a subset of files to another repo and branch", + "source_directory" : "generated-examples/v2", + "target_repo" : "my-target-repo-name", "target_branch" : "v2.2", - "target_directory" : "go" + "target_directory" : "v2-examples" } ] \ 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..82a5234 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_logs/main.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" +) + +// 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/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..fe61acf --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_disk/main.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/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..e957167 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/cmd/get_metrics_process/main.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/project-copy/configs/config.json b/generated-usage-examples/go/atlas-sdk-go/project-copy/configs/config.json new file mode 100644 index 0000000..9034951 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/configs/config.json @@ -0,0 +1,7 @@ +{ + "MONGODB_ATLAS_BASE_URL": "https://cloud.mongodb.com", + "ATLAS_ORG_ID": "", + "ATLAS_PROJECT_ID": "", + "ATLAS_CLUSTER_NAME": "", + "ATLAS_PROCESS_ID": "" +} 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 new file mode 100644 index 0000000..1a74333 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/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/project-copy/go.sum b/generated-usage-examples/go/atlas-sdk-go/project-copy/go.sum new file mode 100644 index 0000000..f7ec5e3 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/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/project-copy/internal/auth/auth.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/auth.go new file mode 100644 index 0000000..2580744 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/auth/auth.go @@ -0,0 +1,43 @@ +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/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..d75df81 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/config_loader.go @@ -0,0 +1,56 @@ +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/project-copy/internal/secrets_loader.go b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/secrets_loader.go new file mode 100644 index 0000000..19f9d49 --- /dev/null +++ b/generated-usage-examples/go/atlas-sdk-go/project-copy/internal/secrets_loader.go @@ -0,0 +1,33 @@ +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 +}