Skip to content

Commit

Permalink
supporting ENVs
Browse files Browse the repository at this point in the history
  • Loading branch information
NorseGaud committed Jun 12, 2024
1 parent a3ac7c2 commit cd4e4b7
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 22 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
*.rdb
*config.y*
dist
.DS_Store
.DS_Store
*.log
*.pid
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ Anklet handles VM [Templates/Tags](https://docs.veertu.com/anka/anka-virtualizat
- `anklet -s stop` to stop the services semi-gracefully (interrupt the plugin at the next context cancellation definition, and still try to cleanup gracefully). This requires that the plugin has properly defined context cancellation checks.
- `anklet -s drain` to stop services, but wait for all jobs to finish gracefully.

It is also possible to use ENVs for several of the items in the config. Here is a list of ENVs that you can use:

| ENV | Description |
| --- | --- |
| ANKLET_WORK_DIR | Absolute path to work directory for anklet (ex: /tmp/) (defaults to `./`) |
| ANKLET_PID_FILE_DIR | Absolute path to pid file directory for anklet (ex: /tmp/) (defaults to `./`) |
| ANKLET_LOG_FILE_DIR | Absolute path to log file directory for anklet (ex: /Users/myUser/Library/Logs/) (defaults to `./`) |
| ANKLET_DATABASE_ENABLED | Whether to enable the database (ex: true) (defaults to `false`) |
| ANKLET_DATABASE_URL | URL of the database (ex: localhost) |
| ANKLET_DATABASE_PORT | Port of the database (ex: 6379) |
| ANKLET_DATABASE_USER | User to use (ex: "") |
| ANKLET_DATABASE_PASSWORD | Password to use (ex: "") |
| ANKLET_DATABASE_DATABASE | Database to use (ex: 0) |

### Database Setup

At the moment we support `redis` 7.x for the database. It can be installed on macOS using homebrew:
Expand Down Expand Up @@ -260,6 +274,21 @@ metrics:
You can see that this requires a database to be running. The aggregator will store the metrics in Redis so that it can serve them up without delay.
It's possible to use ENVs instead of the yml file. This is useful if you want to running anklet metrics aggregator in kubernetes. Here is a list of ENVs that you can use:
| ENV | Description |
| --- | --- |
| ANKLET_METRICS_AGGREGATOR | Whether to enable the aggregator (ex: true) |
| ANKLET_METRICS_PORT | Port to serve aggregator on (ex: 8081) |
| ANKLET_METRICS_URLS | Comma separated list of metrics urls to aggregate (ex: http://127.0.0.1:8080/metrics,http://192.168.1.202:8080/metrics) |
| ANKLET_METRICS_SLEEP_INTERVAL | How many seconds between fetching metrics from each Anklet url defined |
| ANKLET_METRICS_DATABASE_ENABLED | Whether to enable the database (ex: true) |
| ANKLET_METRICS_DATABASE_URL | URL of the database (ex: localhost) |
| ANKLET_METRICS_DATABASE_PORT | Port of the database (ex: 6379) |
| ANKLET_METRICS_DATABASE_DATABASE | Database to use (ex: 0) |
| ANKLET_METRICS_DATABASE_USER | User to use (ex: "") |
| ANKLET_METRICS_DATABASE_PASSWORD | Password to use (ex: "") |
An example response of each format is as follows:
#### JSON
Expand Down
105 changes: 92 additions & 13 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package config
import (
"net/http"
"os"
"strconv"
"strings"
"sync"

"context"
Expand All @@ -15,9 +17,9 @@ type ContextKey string
type Config struct {
Services []Service `yaml:"services"`
Log Log `yaml:"log"`
PidFileDir string `yaml:"pid_file_dir" default:"/tmp/"`
PidFileDir string `yaml:"pid_file_dir"`
LogFileDir string `yaml:"log_file_dir"`
WorkDir string `yaml:"work_dir" default:"/tmp/"`
WorkDir string `yaml:"work_dir"`
Metrics Metrics `yaml:"metrics"`
}

Expand All @@ -26,20 +28,20 @@ type Log struct {
}

type Metrics struct {
Aggregator bool `yaml:"aggregator" default:"false"`
Port string `yaml:"port" default:"8080"` // default set in main.go
Aggregator bool `yaml:"aggregator"`
Port string `yaml:"port"`
MetricsURLs []string `yaml:"metrics_urls"`
SleepInterval int `yaml:"sleep_interval" default:"10"`
SleepInterval int `yaml:"sleep_interval"`
Database Database `yaml:"database"`
}

type Database struct {
URL string `yaml:"url" default:"localhost"`
Port int `yaml:"port" default:"6379"`
User string `yaml:"user" default:""`
Password string `yaml:"password" default:""`
Database int `yaml:"database" default:"0"`
Enabled bool `yaml:"enabled" default:"true"`
URL string `yaml:"url"`
Port int `yaml:"port"`
User string `yaml:"user"`
Password string `yaml:"password"`
Database int `yaml:"database"`
Enabled bool `yaml:"enabled"`
}

type Workflow struct {
Expand All @@ -48,11 +50,11 @@ type Workflow struct {
}

type Service struct {
SleepInterval int `yaml:"sleep_interval" default:"2"`
SleepInterval int `yaml:"sleep_interval"`
Name string `yaml:"name"`
Plugin string `yaml:"plugin"`
Token string `yaml:"token"`
Registration string `yaml:"registration" default:"repo"`
Registration string `yaml:"registration"`
Repo string `yaml:"repo"`
Owner string `yaml:"owner"`
Database Database `yaml:"database"`
Expand All @@ -79,6 +81,83 @@ func LoadConfig(configPath string) (*Config, error) {
return &config, nil
}

func LoadInEnvs(config *Config) (*Config, error) {
envAggregator := os.Getenv("ANKLET_METRICS_AGGREGATOR")
if envAggregator != "" {
config.Metrics.Aggregator = envAggregator == "true"
}

envPort := os.Getenv("ANKLET_METRICS_PORT")
if envPort != "" {
config.Metrics.Port = envPort
}

envMetricsURLs := os.Getenv("ANKLET_METRICS_URLS")
if envMetricsURLs != "" {
config.Metrics.MetricsURLs = strings.Split(envMetricsURLs, ",")
}

envSleepInterval := os.Getenv("ANKLET_METRICS_SLEEP_INTERVAL")
if envSleepInterval != "" {
value, err := strconv.Atoi(envSleepInterval)
if err != nil {
return nil, err
}
config.Metrics.SleepInterval = value
}

envDBEnabled := os.Getenv("ANKLET_METRICS_DATABASE_ENABLED")
if envDBEnabled != "" {
config.Metrics.Database.Enabled = envDBEnabled == "true"
}

envDBUser := os.Getenv("ANKLET_METRICS_DATABASE_USER")
if envDBUser != "" {
config.Metrics.Database.User = envDBUser
}

envDBPassword := os.Getenv("ANKLET_METRICS_DATABASE_PASSWORD")
if envDBPassword != "" {
config.Metrics.Database.Password = envDBPassword
}

envDBURL := os.Getenv("ANKLET_METRICS_DATABASE_URL")
if envDBURL != "" {
config.Metrics.Database.URL = envDBURL
}

envDBPort := os.Getenv("ANKLET_METRICS_DATABASE_PORT")
if envDBPort != "" {
port, err := strconv.Atoi(envDBPort)
if err != nil {
return nil, err
}
config.Metrics.Database.Port = port
}

envDBDatabase := os.Getenv("ANKLET_METRICS_DATABASE_DATABASE")
if envDBDatabase != "" {
database, err := strconv.Atoi(envDBDatabase)
if err != nil {
return nil, err
}
config.Metrics.Database.Database = database
}
workDir := os.Getenv("ANKLET_WORK_DIR")
if workDir != "" {
config.WorkDir = workDir
}
pidFileDir := os.Getenv("ANKLET_PID_FILE_DIR")
if pidFileDir != "" {
config.PidFileDir = pidFileDir
}
logFileDir := os.Getenv("ANKLET_LOG_FILE_DIR")
if logFileDir != "" {
config.LogFileDir = logFileDir
}
return config, nil
}

func GetServiceFromContext(ctx context.Context) Service {
service, ok := ctx.Value(ContextKey("service")).(Service)
if !ok {
Expand Down
25 changes: 17 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ func main() {
if err != nil {
panic(err)
}
loadedConfig, err = config.LoadInEnvs(loadedConfig)
if err != nil {
panic(err)
}

parentCtx = logging.AppendCtx(parentCtx, slog.String("ankletVersion", version))

Expand All @@ -91,6 +95,19 @@ func main() {
}
parentCtx = context.WithValue(parentCtx, config.ContextKey("suffix"), suffix)

logger.DebugContext(parentCtx, "loaded config", slog.Any("config", loadedConfig))
parentCtx = context.WithValue(parentCtx, config.ContextKey("config"), loadedConfig)

if loadedConfig.Log.FileDir == "" {
loadedConfig.Log.FileDir = "./"
}
if loadedConfig.PidFileDir == "" {
loadedConfig.PidFileDir = "./"
}
if loadedConfig.WorkDir == "" {
loadedConfig.WorkDir = "./"
}

daemonContext := &daemon.Context{
PidFileName: loadedConfig.PidFileDir + "anklet" + suffix + ".pid",
PidFilePerm: 0644,
Expand All @@ -113,14 +130,6 @@ func main() {
return
}

logger.DebugContext(parentCtx, "loaded config", slog.Any("config", loadedConfig))
parentCtx = context.WithValue(parentCtx, config.ContextKey("config"), loadedConfig)

if loadedConfig.Log.FileDir == "" {
logger.ErrorContext(parentCtx, "log > file_dir is not set in the configuration; be sure to use an absolute path")
return
}

pluginsPath := filepath.Join(homeDir, ".config", "anklet", "plugins")
parentCtx = context.WithValue(parentCtx, config.ContextKey("globals"), config.Globals{
RunOnce: runOnce,
Expand Down

0 comments on commit cd4e4b7

Please sign in to comment.