Skip to content

Commit

Permalink
Merge pull request #5 from promhippie/multi-credentials
Browse files Browse the repository at this point in the history
Add support for multiple credentials
  • Loading branch information
tboerger authored Mar 26, 2019
2 parents 1ca0f60 + 0d70093 commit e65cf83
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 83 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ coverage.out

.envrc
hetzner.json
config.json
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

* Switch to cloud.drone.io for CI

### Added

* Support multiple credentials and config file

## [0.2.0] - 2019-01-11

### Added
Expand Down
7 changes: 4 additions & 3 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@
[prune]
go-tests = true
unused-packages = true

[[constraint]]
branch = "v2"
name = "gopkg.in/yaml.v2"
73 changes: 56 additions & 17 deletions cmd/prometheus-hetzner-sd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ var (

// ErrMissingHetznerPassword defines the error if hetzner.password is empty.
ErrMissingHetznerPassword = errors.New("Missing required hetzner.password")

// ErrMissingAnyCredentials defines the error if no credentials are provided.
ErrMissingAnyCredentials = errors.New("Missing any credentials")
)

func main() {
Expand Down Expand Up @@ -90,23 +93,38 @@ func main() {
Destination: &cfg.Target.Refresh,
},
&cli.StringFlag{
Name: "hetzner.username",
Value: "",
Usage: "Username for the Hetzner API",
EnvVars: []string{"PROMETHEUS_HETZNER_USERNAME"},
Destination: &cfg.Target.Username,
Name: "hetzner.username",
Value: "",
Usage: "Username for the Hetzner API",
EnvVars: []string{"PROMETHEUS_HETZNER_USERNAME"},
},
&cli.StringFlag{
Name: "hetzner.password",
Value: "",
Usage: "Password for the Hetzner API",
EnvVars: []string{"PROMETHEUS_HETZNER_PASSWORD"},
},
&cli.StringFlag{
Name: "hetzner.password",
Value: "",
Usage: "Password for the Hetzner API",
EnvVars: []string{"PROMETHEUS_HETZNER_PASSWORD"},
Destination: &cfg.Target.Password,
Name: "hetzner.config",
Value: "",
Usage: "Path to Hetzner configuration file",
EnvVars: []string{"PROMETHEUS_HETZNER_CONFIG"},
},
},
Action: func(c *cli.Context) error {
logger := setupLogger(cfg)

if c.IsSet("hetzner.config") {
if err := readConfig(c.String("hetzner.config"), cfg); err != nil {
level.Error(logger).Log(
"msg", "Failed to read config",
"err", err,
)

return err
}
}

if cfg.Target.File == "" {
level.Error(logger).Log(
"msg", ErrMissingOutputFile,
Expand All @@ -115,20 +133,41 @@ func main() {
return ErrMissingOutputFile
}

if cfg.Target.Username == "" {
level.Error(logger).Log(
"msg", ErrMissingHetznerUsername,
if c.IsSet("hetzner.username") && c.IsSet("hetzner.password") {
credentials := config.Credential{
Project: "default",
Username: c.String("hetzner.username"),
Password: c.String("hetzner.password"),
}

cfg.Target.Credentials = append(
cfg.Target.Credentials,
credentials,
)

return ErrMissingHetznerUsername
if credentials.Username == "" {
level.Error(logger).Log(
"msg", ErrMissingHetznerUsername,
)

return ErrMissingHetznerUsername
}

if credentials.Password == "" {
level.Error(logger).Log(
"msg", ErrMissingHetznerPassword,
)

return ErrMissingHetznerPassword
}
}

if cfg.Target.Password == "" {
if len(cfg.Target.Credentials) == 0 {
level.Error(logger).Log(
"msg", ErrMissingHetznerPassword,
"msg", ErrMissingAnyCredentials,
)

return ErrMissingHetznerPassword
return ErrMissingAnyCredentials
}

return action.Server(cfg, logger)
Expand Down
37 changes: 37 additions & 0 deletions cmd/prometheus-hetzner-sd/setup.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package main

import (
"encoding/json"
"errors"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/promhippie/prometheus-hetzner-sd/pkg/config"
)

var (
// ErrConfigFormatInvalid defines the error if ext is unsupported.
ErrConfigFormatInvalid = errors.New("Config extension is not supported")
)

func setupLogger(cfg *config.Config) log.Logger {
var logger log.Logger

Expand Down Expand Up @@ -40,3 +50,30 @@ func setupLogger(cfg *config.Config) log.Logger {
"ts", log.DefaultTimestampUTC,
)
}

func readConfig(file string, cfg *config.Config) error {
if file == "" {
return nil
}

content, err := ioutil.ReadFile(file)

if err != nil {
return err
}

switch strings.ToLower(filepath.Ext(file)) {
case ".yaml", ".yml":
if err = yaml.Unmarshal(content, cfg); err != nil {
return err
}
case ".json":
if err = json.Unmarshal(content, cfg); err != nil {
return err
}
default:
return ErrConfigFormatInvalid
}

return nil
}
31 changes: 31 additions & 0 deletions config/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"server": {
"addr": "0.0.0.0:9000",
"path": "/metrics"
},
"logs": {
"level": "error",
"pretty": false
},
"target": {
"file": "/etc/prometheus/hetzner.json",
"refresh": 30,
"credentials": [
{
"project": "example1",
"username": "#ws+E9WaCWqg",
"password": "nmkEoHQWgnzThGmbfQ6Dojwf"
},
{
"project": "example2",
"username": "#ws+bmnA3gtt",
"password": "xapPbhgoRwEaRAHpKMnxa7YR"
},
{
"project": "example3",
"username": "#ws+Mk6uueNd",
"password": "YmmvhAXAeejpxWJxTzf9kjXm"
}
]
}
}
21 changes: 21 additions & 0 deletions config/example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
server:
addr: 0.0.0.0:9000
path: /metrics

logs:
level: error
pretty: false

target:
file: /etc/prometheus/hetzner.json
refresh: 30
credentials:
- project: example1
username: '#ws+E9WaCWqg'
password: nmkEoHQWgnzThGmbfQ6Dojwf
- project: example2
username: '#ws+bmnA3gtt'
password: xapPbhgoRwEaRAHpKMnxa7YR
- project: example3
username: '#ws+Mk6uueNd'
password: YmmvhAXAeejpxWJxTzf9kjXm
11 changes: 11 additions & 0 deletions docs/content/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ Currently we have not prepared a deployment for Kubernetes, but this is somethin

## Configuration

### Envrionment variables

If you prefer to configure the service with environment variables you can see the available variables below, in case you want to configure multiple accounts with a single service you are forced to use the configuration file as the environment variables are limited to a single account. As the service is pretty lightweight you can even start an instance per account and configure it entirely by the variables, it's up to you.

PROMETHEUS_HETZNER_CONFIG
: Path to Hetzner configuration file, optionally, required for muli credentials

PROMETHEUS_HETZNER_USERNAME
: Username for the Hetzner API, required for authentication

Expand All @@ -63,6 +70,10 @@ PROMETHEUS_HETZNER_OUTPUT_FILE
PROMETHEUS_HETZNER_OUTPUT_REFRESH
: Discovery refresh interval in seconds, defaults to `30`

### Configuration file

Especially if you want to configure multiple accounts within a single service discovery you got to use the configuration file. So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/promhippie/prometheus-hetzner-sd/tree/master/config), there you can always see the latest configuration format. These example configurations include all available options, they also include the default values.

## Labels

* `__meta_hetzner_name`
Expand Down
Loading

0 comments on commit e65cf83

Please sign in to comment.