Skip to content

Commit 3ceac1b

Browse files
authored
(PATCH) Add structured logging, refactoring exporter & config initialization
1 parent 943ef04 commit 3ceac1b

File tree

13 files changed

+587
-530
lines changed

13 files changed

+587
-530
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Example exporter.env:
8989
PC_CLUSTER_NAME=your-pc-cluster-name
9090
PC_CLUSTER_URL=https://your-pc-cluster.yourdomain.com:9440
9191
PC_API_VERSION=v3 (Optional, defaults to v4. Supports v3, v4b1, v4)
92-
CLUSTER_REFRESH_INTERVAL=1800 (Seconds. Optional, defaults to 0, i.e. no refreshing)
92+
CLUSTER_REFRESH_INTERVAL=1800 (Seconds. Optional, defaults to 30 minutes)
9393
CLUSTER_PREFIX=optional-cluster-prefix to filter cluster names
9494
9595
### For HashiCorp Vault only
@@ -98,7 +98,7 @@ VAULT_NAMESPACE=production
9898
VAULT_ENGINE_NAME=NutanixKV2
9999
VAULT_ROLE_ID=12345678-1234-5678-1234-567812345678
100100
VAULT_SECRET_ID=12345678-1234-5678-1234-567812345678
101-
VAULT_REFRESH_INTERVAL=1500 (Seconds. Optional, defaults to 0, i.e. no refreshing)
101+
VAULT_REFRESH_INTERVAL=1500 (Seconds. Optional, defaults to 30 minutes)
102102
PE_TASK_ACCOUNT=PETaskAccount
103103
PC_TASK_ACCOUNT=PCTaskAccount
104104

cmd/nutanix-exporter/main.go

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,58 @@ package main
1717

1818
import (
1919
"context"
20+
"log/slog"
2021
"os"
2122
"os/signal"
2223
"syscall"
2324

24-
"github.com/ingka-group/nutanix-exporter/internal/exporter"
25+
"github.com/ingka-group/nutanix-exporter/internal/auth"
26+
"github.com/ingka-group/nutanix-exporter/internal/config"
27+
"github.com/ingka-group/nutanix-exporter/internal/service"
2528
)
2629

2730
// main is the entrypoint of the exporter
2831
func main() {
2932

30-
// Initialize exporter
31-
go exporter.Init()
33+
// Set up global structured Logging
34+
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
35+
slog.SetDefault(logger)
3236

33-
// Wait for shutdown signal and stop gracefully
37+
// Load configuration
38+
cfg, err := config.NewConfig()
39+
if err != nil {
40+
slog.Error("Failed to load configuration", "error", err)
41+
os.Exit(1)
42+
}
43+
44+
// Create credential provider based on configuration
45+
var credProvider auth.CredentialProvider
46+
if cfg.VaultAddress != "" {
47+
credProvider, err = auth.NewVaultCredentialProvider(cfg)
48+
if err != nil {
49+
slog.Error("Failed to create vault credential provider", "error", err)
50+
os.Exit(1)
51+
}
52+
slog.Info("Using Vault credential provider")
53+
} else {
54+
credProvider = auth.NewEnvCredentialProvider()
55+
slog.Info("Using environment variable credential provider")
56+
}
57+
58+
// Create and start exporter service
59+
exporterService := service.NewExporterService(cfg, credProvider)
60+
if err := exporterService.Start(); err != nil {
61+
slog.Error("Failed to start exporter service", "error", err)
62+
os.Exit(1)
63+
}
64+
65+
// Wait for shutdown signal
3466
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
3567
defer stop()
3668
<-ctx.Done()
37-
stop()
3869

39-
// test
70+
// Stop services and disconnect clients
71+
stop()
72+
exporterService.Stop()
73+
slog.Info("Graceful shutdown completed")
4074
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010

1111
require (
1212
github.com/beorn7/perks v1.0.1 // indirect
13+
github.com/caarlos0/env/v11 v11.3.1 // indirect
1314
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1415
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
1516
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
22
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
4+
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
35
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
46
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
57
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

internal/auth/auth.go

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,10 @@ limitations under the License.
2222

2323
package auth
2424

25-
import (
26-
"log"
27-
"os"
28-
)
29-
3025
// CredentialProvider defines which functions a credential provider for Nutanix
3126
// cluster authentication has to implement.
3227
type CredentialProvider interface {
3328
GetPCCreds(cluster string) (string, string, error)
3429
GetPECreds(cluster string) (string, string, error)
35-
}
36-
37-
// getEnvOrFatal returns the value of the specified environment variable or exits the program.
38-
func getEnvOrFatal(envVar string) string {
39-
value := os.Getenv(envVar)
40-
if value == "" {
41-
log.Fatalf("%s environment variable is not set", envVar)
42-
}
43-
return value
30+
Refresh() error // For refreshable providers like Vault
4431
}

internal/auth/env.go

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,33 @@ import (
2626
// cluster authentication credentials from environment variables.
2727
type EnvCredentialProvider struct{}
2828

29-
// ConvertClusterName changes any characters that should not be used in
30-
// environment variables to an underscore (_).
31-
func ConvertClusterName(cluster string) string {
32-
cluster = strings.ToUpper(cluster)
33-
34-
r, _ := regexp.Compile("[^A-Z_0-9]+")
35-
cluster = r.ReplaceAllString(cluster, "_")
29+
// NewEnvCredentialProvider creates a new instance of EnvCredentialProvider.
30+
func NewEnvCredentialProvider() *EnvCredentialProvider {
31+
return &EnvCredentialProvider{}
32+
}
3633

37-
return cluster
34+
// Refresh is a no-op for the EnvCredentialProvider since it does not maintain a state.
35+
func (e *EnvCredentialProvider) Refresh() error {
36+
return nil
3837
}
3938

4039
// getEnvVarsForCluster generates the names for the environment variables
4140
// that have to be used for providing login credentials of a Nutanix cluster.
42-
func getEnvVarsForCluster(cluster string, isPC bool) (string, string) {
43-
var evU, evP string
44-
41+
func (e *EnvCredentialProvider) getEnvVarsForCluster(cluster string, isPC bool) (string, string) {
4542
if isPC {
46-
evU = "PC_USERNAME"
47-
evP = "PC_PASSWORD"
48-
} else {
49-
evU = "PE_USERNAME_" + ConvertClusterName(cluster)
50-
evP = "PE_PASSWORD_" + ConvertClusterName(cluster)
43+
return "PC_USERNAME", "PC_PASSWORD"
5144
}
5245

53-
return evU, evP
46+
convertedCluster := e.convertClusterName(cluster)
47+
return "PE_USERNAME_" + convertedCluster, "PE_PASSWORD_" + convertedCluster
5448
}
5549

5650
// getCreds reads the appropriate environment variables and returns the username and password
5751
// for the provided cluster name.
5852
//
5953
// If isPC is true the credentials for Prism Central will be returned, otherwise those for Prism Element.
60-
func getCreds(cluster string, isPC bool) (string, string, error) {
61-
evU, evP := getEnvVarsForCluster(cluster, isPC)
54+
func (e *EnvCredentialProvider) getCreds(cluster string, isPC bool) (string, string, error) {
55+
evU, evP := e.getEnvVarsForCluster(cluster, isPC)
6256

6357
username := os.Getenv(evU)
6458
if username == "" {
@@ -73,14 +67,19 @@ func getCreds(cluster string, isPC bool) (string, string, error) {
7367
return username, password, nil
7468
}
7569

76-
// GetPCCreds returns the username and password for the specified Prism Central cluster
77-
func (evCP *EnvCredentialProvider) GetPCCreds(cluster string) (string, string, error) {
78-
79-
return getCreds(cluster, true)
70+
// GetPCCreds retrieves the username and password for a given cluster from environment variables.
71+
func (e *EnvCredentialProvider) GetPCCreds(cluster string) (string, string, error) {
72+
return e.getCreds(cluster, true)
8073
}
8174

82-
// GetPECreds returns the username and password for the specified Prism Element cluster
83-
func (evCP *EnvCredentialProvider) GetPECreds(cluster string) (string, string, error) {
75+
// GetPECreds retrieves the username and password for a given cluster from environment variables.
76+
func (e *EnvCredentialProvider) GetPECreds(cluster string) (string, string, error) {
77+
return e.getCreds(cluster, false)
78+
}
8479

85-
return getCreds(cluster, false)
80+
// convertClusterName converts the cluster name to uppercase and replaces non-alphanumeric characters with underscores.
81+
func (e *EnvCredentialProvider) convertClusterName(cluster string) string {
82+
cluster = strings.ToUpper(cluster)
83+
r, _ := regexp.Compile("[^A-Z_0-9]+")
84+
return r.ReplaceAllString(cluster, "_")
8685
}

0 commit comments

Comments
 (0)