-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathmain.go
164 lines (132 loc) · 5.09 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2021 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"errors"
"fmt"
"os"
"time"
nrClient "github.com/newrelic/newrelic-client-go/v2/newrelic"
"github.com/newrelic/newrelic-client-go/v2/pkg/nrdb"
"github.com/newrelic/newrelic-client-go/v2/pkg/region"
"github.com/spf13/pflag"
"k8s.io/component-base/logs"
"k8s.io/component-base/metrics/legacyregistry"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
"sigs.k8s.io/custom-metrics-apiserver/pkg/provider"
"sigs.k8s.io/yaml"
"github.com/newrelic/newrelic-k8s-metrics-adapter/internal/adapter"
"github.com/newrelic/newrelic-k8s-metrics-adapter/internal/provider/cache"
"github.com/newrelic/newrelic-k8s-metrics-adapter/internal/provider/newrelic"
)
const (
// DefaultConfigPath is a path from where configuration will be read.
DefaultConfigPath = "/etc/newrelic/adapter/config.yaml"
// NewRelicAPIKeyEnv is an environment variable name which must be set with a valid NewRelic license key for
// adapter to run.
NewRelicAPIKeyEnv = "NEWRELIC_API_KEY"
// ClusterNameEnv is an environment variable name which will be read for filtering cluster-scoped metrics.
ClusterNameEnv = "CLUSTER_NAME"
// NrdbClientMaxTimeoutSeconds is the maximum timeout that could be set to the nrdb client.
NrdbClientMaxTimeoutSeconds = 120
)
// ConfigOptions represents supported configuration options for metric-adapter.
type ConfigOptions struct {
AccountID int64 `json:"accountID"`
ExternalMetrics map[string]newrelic.Metric `json:"externalMetrics"`
Region string `json:"region"`
CacheTTLSeconds int64 `json:"cacheTTLSeconds"`
NrdbClientTimeoutSeconds int `json:"nrdbClientTimeoutSeconds"`
}
// Run reads configuration file and environment variables to configure and run the adapter.
func Run(ctx context.Context, args []string) error {
flagSet := pflag.NewFlagSet(adapter.Name, pflag.ContinueOnError)
configPath := flagSet.String("config-file", DefaultConfigPath, "Path to read config file from")
err := adapter.ParseFlags(args, flagSet, nil)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
return nil
}
return fmt.Errorf("parsing given flags: %w", err)
}
config, err := loadConfiguration(*configPath)
if err != nil {
return fmt.Errorf("loading configuration: %w", err)
}
if config.Region != "" {
if _, err := region.Parse(config.Region); err != nil {
return fmt.Errorf("parsing region %q: %w", config.Region, err)
}
}
if config.NrdbClientTimeoutSeconds > NrdbClientMaxTimeoutSeconds {
config.NrdbClientTimeoutSeconds = NrdbClientMaxTimeoutSeconds
}
clientOptions := []nrClient.ConfigOption{
nrClient.ConfigPersonalAPIKey(os.Getenv(NewRelicAPIKeyEnv)),
nrClient.ConfigRegion(config.Region),
nrClient.ConfigHTTPTimeout(time.Duration(config.NrdbClientTimeoutSeconds) * time.Second),
}
// The NEWRELIC_API_KEY is read from an envVar populated thanks to a k8s secret.
c, err := nrClient.New(clientOptions...)
if err != nil {
return fmt.Errorf("creating NewRelic client: %w", err)
}
externalMetricsProvider, err := externalMetricsProvider(config, &c.Nrdb)
if err != nil {
return fmt.Errorf("creating external metrics provider: %w", err)
}
options := adapter.Options{
Args: args,
ExtraFlags: flagSet,
ExternalMetricsProvider: externalMetricsProvider,
}
a, err := adapter.NewAdapter(options)
if err != nil {
return fmt.Errorf("initializing adapter: %w", err)
}
return a.Run(ctx.Done()) //nolint:wrapcheck // Don't wrap as otherwise error annotations will be duplicated.
}
func externalMetricsProvider(config *ConfigOptions, nrdb *nrdb.Nrdb) (provider.ExternalMetricsProvider, error) {
providerOptions := newrelic.ProviderOptions{
ExternalMetrics: config.ExternalMetrics,
NRDBClient: nrdb,
AccountID: config.AccountID,
ClusterName: os.Getenv(ClusterNameEnv),
RegisterFunc: legacyregistry.Register,
}
directProvider, err := newrelic.NewDirectProvider(providerOptions)
if err != nil {
return nil, fmt.Errorf("creating direct provider: %w", err)
}
cacheOptions := cache.ProviderOptions{
ExternalProvider: directProvider,
CacheTTLSeconds: config.CacheTTLSeconds,
RegisterFunc: legacyregistry.Register,
}
cacheProvider, err := cache.NewCacheProvider(cacheOptions)
if err != nil {
return nil, fmt.Errorf("creating cache provider: %w", err)
}
return cacheProvider, nil
}
func main() {
logs.InitLogs()
defer logs.FlushLogs()
klog.Infof("Starting NewRelic metrics adapter")
if err := Run(signals.SetupSignalHandler(), os.Args); err != nil {
klog.Fatalf("Running adapter failed: %v", err)
}
}
func loadConfiguration(configPath string) (*ConfigOptions, error) {
b, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("reading config file: %w", err)
}
config := &ConfigOptions{}
if err = yaml.UnmarshalStrict(b, config); err != nil {
return nil, fmt.Errorf("unmarshalling config: %w", err)
}
return config, nil
}