Skip to content

Commit 6721dea

Browse files
author
Christian González Di Antonio
committed
refactored
1 parent 74f9f60 commit 6721dea

File tree

14 files changed

+161
-342
lines changed

14 files changed

+161
-342
lines changed

.github/workflows/master.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ jobs:
4040
- name: Check code modifications
4141
run: git diff --exit-code
4242

43+
- name: Coveralls
44+
uses: coverallsapp/github-action@master
45+
with:
46+
github-token: ${{ secrets.GITHUB_TOKEN }}
47+
4348
build:
4449
name: Build
4550
needs: test

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@ Prometheus exporter for AWS CloudWatch
99
This exporter used the AWS CloudWatch GetMetricsData API call, please it is important you read
1010
* https://aws.amazon.com/premiumsupport/knowledge-center/cloudwatch-getmetricdata-api/
1111

12-
## Config files
12+
## Configuration
13+
14+
The configuration could be set using 3 ways:
15+
16+
1. Configuration Files (i.e.: ./server.yaml, ./credentials.yaml, ./metrics.yaml)
17+
2. Environment Variables (i.e.: SERVER_PORT, AWS_REGION, AWS_PROFILE, etc)
18+
3. Program Flags (i.e.: --serverPort, --region, --profile)
19+
20+
The precedence is in the same order of the list, so, if you define values into `server.yaml` and then
21+
the same configuration key is defined as a `Env Var` this last will replace the file value.
22+
23+
### Configuration Files
1324

1425
* [server.yaml](docs/server.md)
1526
* [credentials.yaml](docs/credentials.md)
1627
* [metrics.yaml](docs/metrics.md)
1728

29+
1830
## Development / Contributing
1931

2032
### Building and release tools

cmd/metrics.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,12 @@ func init() {
9595

9696
func getCmd(cmd *cobra.Command, args []string) {
9797

98-
ReadAndValidateMetricsFromFiles()
98+
loadFromMetricsFiles(&conf)
99+
validateMetricsQueries(&conf)
100+
101+
if conf.Server.Debug {
102+
log.Debug(conf.ToJSON())
103+
}
99104

100105
startTime, endTime, period := metrics.GetTimeStamps(time.Now(), conf.Application.MetricStatPeriod, conf.Application.MetricTimeWindow)
101106
log.Debugf("Start Time: %s", startTime.Format(time.RFC3339))
@@ -109,7 +114,7 @@ func getCmd(cmd *cobra.Command, args []string) {
109114
svc := cloudwatch.New(sess)
110115
mdo, err := svc.GetMetricData(mdi)
111116
if err != nil {
112-
log.Errorf("Error getting metrics %v", err)
117+
log.Fatalf("Error getting metrics: %v", err)
113118
}
114119

115120
var outMetrics []byte
@@ -137,24 +142,34 @@ func getCmd(cmd *cobra.Command, args []string) {
137142
log.Panic(err)
138143
}
139144
} else {
140-
fmt.Println(string(outMetrics))
145+
log.Println(string(outMetrics))
141146
}
142147
}
143148

144149
func displayPromDescCmd(cmd *cobra.Command, args []string) {
145150

146-
ReadAndValidateConfFromFiles()
151+
loadFromMetricsFiles(&conf)
152+
validateMetricsQueries(&conf)
153+
154+
if conf.Server.Debug {
155+
log.Debug(conf.ToJSON())
156+
}
147157

148158
m := metrics.New(&conf)
149159

150160
for _, md := range m.GetMetricsDesc() {
151-
fmt.Println(md.String())
161+
log.Println(md.String())
152162
}
153163
}
154164

155165
func collectCmd(cmd *cobra.Command, args []string) {
156166

157-
ReadAndValidateConfFromFiles()
167+
loadFromMetricsFiles(&conf)
168+
validateMetricsQueries(&conf)
169+
170+
if conf.Server.Debug {
171+
log.Debug(conf.ToJSON())
172+
}
158173

159174
m := metrics.New(&conf)
160175
sess := awshelper.NewSession(&conf.AWS)

cmd/root.go

Lines changed: 28 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
1212
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
15+
1516
*/
1617
package cmd
1718

@@ -29,7 +30,7 @@ import (
2930
"github.com/slashdevops/aws_cloudwatch_exporter/config"
3031
"github.com/spf13/cobra"
3132
"github.com/spf13/viper"
32-
"gopkg.in/yaml.v2"
33+
"gopkg.in/yaml.v3"
3334
)
3435

3536
const (
@@ -88,24 +89,6 @@ func init() {
8889
}
8990

9091
// AWS Credentials conf
91-
// AccessKeyID
92-
rootCmd.PersistentFlags().StringVar(&conf.AWS.AccessKeyID, "access_key_id", "", "The AWS AccessKeyID, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
93-
if err := viper.BindPFlag("aws.access_key_id", rootCmd.PersistentFlags().Lookup("access_key_id")); err != nil {
94-
log.Error(err)
95-
}
96-
97-
// SecretAccessKey
98-
rootCmd.PersistentFlags().StringVar(&conf.AWS.SecretAccessKey, "secret_access_key", "", "The AWS SecretAccessKey, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
99-
if err := viper.BindPFlag("aws.secret_access_key", rootCmd.PersistentFlags().Lookup("secret_access_key")); err != nil {
100-
log.Error(err)
101-
}
102-
103-
// SessionToken
104-
rootCmd.PersistentFlags().StringVar(&conf.AWS.SessionToken, "session_token", "", "The AWS SessionToken, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
105-
if err := viper.BindPFlag("aws.session_token", rootCmd.PersistentFlags().Lookup("session_token")); err != nil {
106-
log.Error(err)
107-
}
108-
10992
// Region
11093
rootCmd.PersistentFlags().StringVar(&conf.AWS.Region, "region", "", "The AWS Region, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
11194
if err := viper.BindPFlag("aws.region", rootCmd.PersistentFlags().Lookup("region")); err != nil {
@@ -123,48 +106,6 @@ func init() {
123106
if err := viper.BindPFlag("aws.role_arn", rootCmd.PersistentFlags().Lookup("role_arn")); err != nil {
124107
log.Error(err)
125108
}
126-
127-
// RoleSessionName
128-
rootCmd.PersistentFlags().StringVar(&conf.AWS.RoleSessionName, "role_session_name", "", "The AWS RoleSessionName, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
129-
if err := viper.BindPFlag("aws.role_session_name", rootCmd.PersistentFlags().Lookup("role_session_name")); err != nil {
130-
log.Error(err)
131-
}
132-
133-
// WebIdentityTokenFile
134-
rootCmd.PersistentFlags().StringVar(&conf.AWS.WebIdentityTokenFile, "web_identity_token_file", "", "The AWS WebIdentityTokenFile, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
135-
if err := viper.BindPFlag("aws.web_identity_token_file", rootCmd.PersistentFlags().Lookup("web_identity_token_file")); err != nil {
136-
log.Error(err)
137-
}
138-
139-
// ExternalID
140-
rootCmd.PersistentFlags().StringVar(&conf.AWS.ExternalID, "external_id", "", "The AWS ExternalID, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
141-
if err := viper.BindPFlag("aws.external_id", rootCmd.PersistentFlags().Lookup("external_id")); err != nil {
142-
log.Error(err)
143-
}
144-
145-
// MFASerial
146-
rootCmd.PersistentFlags().StringVar(&conf.AWS.MFASerial, "mfa_serial", "", "The AWS MFASerial, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
147-
if err := viper.BindPFlag("aws.mfa_serial", rootCmd.PersistentFlags().Lookup("mfa_serial")); err != nil {
148-
log.Error(err)
149-
}
150-
151-
// SharedConfigState
152-
rootCmd.PersistentFlags().BoolVar(&conf.AWS.SharedConfigState, "shared_config_state", true, "The AWS SharedConfigState, see: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html")
153-
if err := viper.BindPFlag("aws.shared_config_state", rootCmd.PersistentFlags().Lookup("shared_config_state")); err != nil {
154-
log.Error(err)
155-
}
156-
157-
// SharedCredentialsFile
158-
rootCmd.PersistentFlags().StringSliceVar(&conf.AWS.SharedCredentialsFile, "shared_credential_file", nil, "The AWS SharedCredentialsFile, example: --shared_credential_file ~/.aws/credentials --shared_credential_file /etc/aws/credentials")
159-
if err := viper.BindPFlag("aws.shared_credential_file", rootCmd.PersistentFlags().Lookup("shared_credential_file")); err != nil {
160-
log.Error(err)
161-
}
162-
163-
// ConfigFile
164-
rootCmd.PersistentFlags().StringSliceVar(&conf.AWS.ConfigFile, "config_file", nil, "The AWS ConfigFile, example: --config_file ~/.aws/config --config_file /etc/aws/config")
165-
if err := viper.BindPFlag("aws.config_file", rootCmd.PersistentFlags().Lookup("config_file")); err != nil {
166-
log.Error(err)
167-
}
168109
}
169110

170111
func initConfig() {
@@ -201,80 +142,43 @@ func initConfig() {
201142
conf.Application.BuildInfo = version.BuildContext()
202143
}
203144

204-
// this will be used for every commands that needs conf in files
205-
func ReadAndValidateConfFromFiles() {
206-
// Read env vars equals as the mapstructure defined into the config.go
207-
viper.AutomaticEnv()
208-
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
209-
210-
loadFromConfigFiles(&conf)
211-
loadFromMetricsFiles(&conf)
212-
validateMetricsQueries(&conf)
145+
// Unmarshall Yaml files into c config structure
146+
func loadFromConfigFiles(fileName string, c *config.All) {
213147

214-
// expose all the configuration, just to check
215-
if conf.Server.Debug {
216-
log.Debug(conf.ToJSON())
217-
// log.VersionInfo(conf.ToYAML())
148+
if !fileExists(fileName) {
149+
log.Warnf("The file %s doesn't exist, I will try to use configuration values from flags or ENV vars", fileName)
218150
}
219-
}
220151

221-
// this will be used for every commands that needs conf in files
222-
func ReadAndValidateMetricsFromFiles() {
152+
log.Infof("Reading configuration file: %s", fileName)
153+
154+
// fileNameNoExt := strings.TrimSuffix(file, filepath.Ext(file))
155+
156+
log.Debugf("Parsing configuration file path: %s", fileName)
157+
log.Debugf("File: %s", filepath.Base(fileName))
158+
// log.Debugf("File without ext: %s", fileNameNoExt)
159+
log.Debugf("Location: %s", filepath.Dir(fileName))
160+
log.Debugf("File ext: %s", filepath.Ext(fileName)[1:])
161+
162+
// viper.SetConfigName(fileNameNoExt)
163+
viper.SetConfigName(filepath.Base(fileName))
164+
viper.AddConfigPath(filepath.Dir(fileName))
165+
viper.SetConfigType(filepath.Ext(fileName)[1:])
166+
223167
// Read env vars equals as the mapstructure defined into the config.go
224168
viper.AutomaticEnv()
225169
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
226170

227-
loadFromMetricsFiles(&conf)
228-
validateMetricsQueries(&conf)
229-
230-
// expose all the configuration, just to check
231-
if conf.Server.Debug {
232-
log.Debug(conf.ToJSON())
233-
// log.VersionInfo(conf.ToYAML())
171+
log.Debugf("Loading configuration from file: %s", fileName)
172+
if err := viper.ReadInConfig(); err != nil {
173+
log.Fatalf("Error reading config file, %s", err)
234174
}
235-
}
236175

237-
// Unmarshall Yaml files into c config structure
238-
func loadFromConfigFiles(c *config.All) {
239-
// Config files to be load
240-
files := []string{
241-
c.Application.ServerFile,
242-
c.Application.CredentialsFile,
176+
log.Debugf("Filling configuration structure from file: %s", fileName)
177+
err := viper.Unmarshal(&c)
178+
if err != nil {
179+
log.Fatalf("Unable to decode into struct, %v", err)
243180
}
244181

245-
for _, file := range files {
246-
247-
if !fileExists(file) {
248-
log.Warnf("The file %s doesn't exist, I will try to use configuration values from flags or ENV vars", file)
249-
break
250-
}
251-
252-
log.Infof("Reading configuration file: %s", file)
253-
254-
// fileNameNoExt := strings.TrimSuffix(file, filepath.Ext(file))
255-
256-
log.Debugf("Parsing configuration file path: %s", file)
257-
log.Debugf("File: %s", filepath.Base(file))
258-
// log.Debugf("File without ext: %s", fileNameNoExt)
259-
log.Debugf("Location: %s", filepath.Dir(file))
260-
log.Debugf("File ext: %s", filepath.Ext(file)[1:])
261-
262-
// viper.SetConfigName(fileNameNoExt)
263-
viper.SetConfigName(filepath.Base(file))
264-
viper.AddConfigPath(filepath.Dir(file))
265-
viper.SetConfigType(filepath.Ext(file)[1:])
266-
267-
log.Debugf("Loading configuration from file: %s", file)
268-
if err := viper.ReadInConfig(); err != nil {
269-
log.Fatalf("Error reading config file, %s", err)
270-
}
271-
272-
log.Debugf("Filling configuration structure from file: %s", file)
273-
err := viper.Unmarshal(&c)
274-
if err != nil {
275-
log.Fatalf("Unable to decode into struct, %v", err)
276-
}
277-
}
278182
}
279183

280184
// Unmarshall Yaml files into c config structure

cmd/server.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,15 @@ func init() {
110110
}
111111

112112
func startCmd(cmd *cobra.Command, args []string) {
113-
ReadAndValidateConfFromFiles()
113+
114+
loadFromConfigFiles(conf.Application.ServerFile, &conf)
115+
loadFromConfigFiles(conf.Application.CredentialsFile, &conf)
116+
loadFromMetricsFiles(&conf)
117+
validateMetricsQueries(&conf)
118+
119+
if conf.Server.Debug {
120+
log.Debug(conf.ToJSON())
121+
}
114122

115123
m := metrics.New(&conf)
116124
sess := awshelper.NewSession(&conf.AWS)
@@ -128,6 +136,11 @@ func startCmd(cmd *cobra.Command, args []string) {
128136
// Debug & Profiling
129137
if conf.Server.Debug {
130138
mux.HandleFunc("/debug/pprof/", pprof.Index)
139+
mux.HandleFunc("/debug/pprof/heap", pprof.Index)
140+
mux.HandleFunc("/debug/pprof/mutex", pprof.Index)
141+
mux.HandleFunc("/debug/pprof/goroutine", pprof.Index)
142+
mux.HandleFunc("/debug/pprof/threadcreate", pprof.Index)
143+
mux.HandleFunc("/debug/pprof/block", pprof.Index)
131144
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
132145
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
133146
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)

config/config.go

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,9 @@ type AWSConf struct {
110110
}
111111

112112
type AWS struct {
113-
AccessKeyID string `mapstructure:"access_key_id" json:"accessKeyID" yaml:"accessKeyID"`
114-
SecretAccessKey string `mapstructure:"secret_access_key" json:"secretAccessKey" yaml:"secretAccessKey"`
115-
SessionToken string `mapstructure:"session_token" json:"sessionToken" yaml:"sessionToken"`
116-
Region string `mapstructure:"region" json:"region" yaml:"region"`
117-
Profile string `mapstructure:"profile" json:"profile" yaml:"profile"`
118-
RoleArn string `mapstructure:"role_arn" json:"roleArn" yaml:"roleArn"`
119-
RoleSessionName string `mapstructure:"role_session_name" json:"roleSessionName" yaml:"roleSessionName"`
120-
WebIdentityTokenFile string `mapstructure:"web_identity_token_file" json:"webIdentityTokenFile" yaml:"webIdentityTokenFile"`
121-
ExternalID string `mapstructure:"external_id" json:"externalID" yaml:"externalID"`
122-
MFASerial string `mapstructure:"mfa_serial" json:"MFASerial" yaml:"MFASerial"`
123-
SharedConfigState bool `mapstructure:"shared_config_state" json:"sharedConfigState" yaml:"sharedConfigState"`
124-
SharedCredentialsFile []string `mapstructure:"shared_credential_file" json:"sharedCredentialsFile" yaml:"sharedCredentialsFile"`
125-
ConfigFile []string `mapstructure:"config_file" json:"configFile" yaml:"configFile"`
113+
Region string `mapstructure:"region" json:"region" yaml:"region"`
114+
Profile string `mapstructure:"profile" json:"profile" yaml:"profile"`
115+
RoleArn string `mapstructure:"role_arn" json:"roleArn" yaml:"roleArn"`
126116
}
127117

128118
// This is a convenient structure to allow config files nested (MetricDataQueries.[keys])

credentials.yaml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11
aws:
2-
access_key_id: ""
3-
secret_access_key: ""
4-
session_token: ""
52
region: ""
63
profile: ""
7-
role_arn: ""
8-
role_session_name: ""
9-
web_identity_token_file: ""
10-
external_id: ""
11-
mfa_serial: ""
12-
shared_config_state: ""
13-
shared_credential_file: ""
14-
config_file: ""
4+
role_arn: ""

docs/credentials.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,13 @@ This is the credentials' configuration file options
44

55
```yaml
66
aws:
7-
access_key_id: ""
8-
secret_access_key: ""
97
session_token: ""
108
region: ""
119
profile: ""
1210
role_arn: ""
1311
role_session_name: ""
1412
web_identity_token_file: ""
1513
external_id: ""
16-
mfa_serial: ""
17-
shared_config_state: ""
18-
shared_credential_file: ""
19-
config_file: ""
2014
```
2115
2216
## Help links

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,5 @@ require (
2424
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
2525
google.golang.org/protobuf v1.24.0 // indirect
2626
gopkg.in/ini.v1 v1.57.0 // indirect
27-
gopkg.in/yaml.v2 v2.3.0
2827
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
2928
)

0 commit comments

Comments
 (0)