Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #14 from aserto-dev/179159782/config_file
Browse files Browse the repository at this point in the history
load plugin settings from config file
  • Loading branch information
florindragos committed Sep 16, 2021
2 parents ed8d39e + 4338092 commit 54d6b7f
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 40 deletions.
6 changes: 6 additions & 0 deletions cmd/aserto-idp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"log"
"os"
"strings"

"github.com/alecthomas/kong"
"github.com/aserto-dev/aserto-idp/pkg/cc"
Expand Down Expand Up @@ -84,6 +85,11 @@ func main() {

ctx := kong.Parse(&cli, options...)

err = c.LoadConfig(strings.TrimSpace(cli.Config))
if err != nil {
c.Log.Fatal().Msg(err.Error())
}

err = ctx.Run(c)

ctx.FatalIfErrorf(err)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ require (
github.com/magefile/mage v1.11.0
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.23.0
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 // indirect
golang.org/x/text v0.3.7 // indirect
Expand Down
174 changes: 173 additions & 1 deletion go.sum

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions pkg/cc/cc.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ import (
"strconv"
"strings"

"github.com/aserto-dev/aserto-idp/pkg/cc/config"
"github.com/aserto-dev/aserto-idp/pkg/provider"
"github.com/aserto-dev/go-utils/logger"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)

// CC contains dependencies that are cross cutting and are needed in most
// of the providers that make up this application
type CC struct {
Context context.Context
Config *config.Config
Log *zerolog.Logger
defaultProvider provider.Provider
providers map[string]provider.Provider
Expand All @@ -36,6 +39,7 @@ func New() *CC {

ctx := CC{
Context: context.Background(),
Config: &config.Config{},
Log: log,
providers: make(map[string]provider.Provider),
}
Expand Down Expand Up @@ -94,6 +98,26 @@ func (c *CC) Dispose() {
c.defaultProvider.Kill()
}

// LoadConfig loads the plugin and logger config from a configuration file
func (c *CC) LoadConfig(path string) error {
cfg, err := config.NewConfig(path, c.Log)
if err != nil {
return errors.Wrap(err, "error while loading configuration")
}
c.Log.Debug().Msgf("using config file %s", path)
c.Config = cfg

if cfg.Logging != nil && c.Log.GetLevel() == zerolog.ErrorLevel {
log, err := logger.NewLogger(os.Stdout, cfg.Logging)
if err != nil {
c.Log.Warn().Msgf("failed to load logger from config file '%s'", err.Error())
} else {
c.Log = log
}
}
return nil
}

func getLogLevel() zerolog.Level {
logLevel := zerolog.ErrorLevel

Expand Down
73 changes: 73 additions & 0 deletions pkg/cc/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package config

import (
"fmt"
"os"
"strings"

"github.com/aserto-dev/go-utils/logger"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/spf13/viper"
)

type Config struct {
Logging *logger.Config `mapstructure:"logging"`
Plugins map[string]map[string]interface{} `mapstructure:"plugins"`
}

// Loads the config from a file.
func NewConfig(configPath string, log *zerolog.Logger) (*Config, error) {
if configPath == "" {
return &Config{}, nil
}
configLogger := log.With().Str("component", "config").Logger()
log = &configLogger

exists, err := fileExists(configPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to determine if the config file %s exists", configPath)
}

if !exists {
return nil, errors.New(fmt.Sprintf("Config file %s does not exist", configPath))
}

v := viper.New()
v.SetConfigFile("yaml")
v.AddConfigPath(".")
v.SetConfigFile(configPath)
v.SetEnvPrefix("ASERTO_IDP_CLI")
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))

err = v.ReadInConfig()
if err != nil {
return nil, errors.Wrapf(err, "failed to open config file '%s'", configPath)
}
v.AutomaticEnv()

cfg := new(Config)
err = v.UnmarshalExact(cfg)
if err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal config file '%s'", configPath)
}

if cfg.Logging != nil {
cfg.Logging.LogLevelParsed, err = zerolog.ParseLevel(cfg.Logging.LogLevel)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse log level %s", cfg.Logging.LogLevel)
}
}

return cfg, nil
}

func fileExists(path string) (bool, error) {
if _, err := os.Stat(path); err == nil {
return true, nil
} else if os.IsNotExist(err) {
return false, nil
} else {
return false, errors.Wrapf(err, "failed to stat file '%s'", path)
}
}
108 changes: 108 additions & 0 deletions pkg/cc/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package config

import (
"fmt"
"os"
"path/filepath"
"testing"

"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)

var log zerolog.Logger

func getConfigFile(content string, t *testing.T) string {
tmpDir := t.TempDir()

configFilePath := filepath.Join(tmpDir, fmt.Sprintf("%s.yaml", t.Name()))
configFile, err := os.Create(configFilePath)
if err != nil {
t.Error("cannot create configuration file")
}
defer configFile.Close()

_, err = configFile.WriteString(content)
if err != nil {
t.Error(err)
}
return configFilePath
}

func TestConfigDoesNotExist(t *testing.T) {
assert := require.New(t)
configPath := filepath.Join(t.TempDir(), "not_exist.yaml")

cfg, err := NewConfig(configPath, &log)
assert.NotNil(err)
assert.Nil(cfg)

}

func TestConfigFromFile(t *testing.T) {
assert := require.New(t)
content := `
---
logging:
log_level: trace
plugins:
json:
file: user_import.json
aserto:
tenant: "00000000-0000-0000-0000-000000000000"
authorizer: "authorizer.prod.aserto.com:8443"
api_key: "0000000000000000000000000000000000000000000000000000"
`

configFilePath := getConfigFile(content, t)
cfg, err := NewConfig(configFilePath, &log)

assert.Nil(err)
assert.NotNil(cfg.Plugins["json"])
assert.NotNil(cfg.Plugins["aserto"])
assert.Equal(zerolog.LevelTraceValue, cfg.Logging.LogLevel)
assert.Nil(cfg.Plugins["ion"])

jsonSettings := cfg.Plugins["json"]
assert.Equal("user_import.json", jsonSettings["file"])
assert.Nil(jsonSettings["nosetting"])

asertoSettings := cfg.Plugins["aserto"]
assert.Equal("00000000-0000-0000-0000-000000000000", asertoSettings["tenant"])
assert.Equal("authorizer.prod.aserto.com:8443", asertoSettings["authorizer"])
assert.Equal("0000000000000000000000000000000000000000000000000000", asertoSettings["api_key"])

}

func TestConfigFromFileNoPlugins(t *testing.T) {
assert := require.New(t)
content := `
---
logging:
log_level: error
`

configFilePath := getConfigFile(content, t)
cfg, err := NewConfig(configFilePath, &log)

assert.Nil(err)
assert.Nil(cfg.Plugins["aserto"])
assert.Equal(zerolog.ErrorLevel, cfg.Logging.LogLevelParsed)
}

func TestConfigFromFileNoPLogging(t *testing.T) {
assert := require.New(t)
content := `
---
plugins:
json:
file: user_import.json
`

configFilePath := getConfigFile(content, t)
cfg, err := NewConfig(configFilePath, &log)

assert.Nil(err)
assert.Nil(cfg.Logging)
}
4 changes: 2 additions & 2 deletions pkg/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

type CLI struct {
Config string `short:"c" type:"path" help:"Path to the config file. Any argument provided to the CLI will take precedence."`
Version VersionCmd `cmd:"" help:"version information"`
Verbosity int `short:"v" type:"counter" help:"Use to increase output verbosity."`
Debug bool `name:"debug" env:"ASERTO_DEBUG" help:"enable debug logging"`
kong.Plugins
}

Expand All @@ -24,7 +24,7 @@ type VersionCmd struct {
}

func (cmd *VersionCmd) Run(c *cc.CC) error {
fmt.Fprintf(c.Log, "%s - %s (%s)\n",
fmt.Printf("%s - %s (%s)\n",
x.AppName,
version.GetInfo().String(),
x.AppVersionTag,
Expand Down
12 changes: 7 additions & 5 deletions pkg/cmd/plugin/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,14 @@ type ExportCmd struct {
}

func (cmd *ExportCmd) Run(app *kong.Kong, context *kong.Context, c *cc.CC) error {
configs, err := getPbStructForNode(context.Selected().Parent)
if err != nil {
return err
}

users := make(chan *api.User, 10)
done := make(chan bool, 1)
errc := make(chan error, 1)
result := make(chan *proto.ImportResponse, 1)

defaultProviderConfigs, err := getPbStructForNode(context.Path[0].Node())
defaultProviderName := c.GetDefaultProvider().GetName()
defaultProviderConfigs, err := getPbStructForNode(c.Config.Plugins[defaultProviderName], context.Path[0].Node())
if err != nil {
return err
}
Expand All @@ -49,6 +46,11 @@ func (cmd *ExportCmd) Run(app *kong.Kong, context *kong.Context, c *cc.CC) error

providerName := context.Selected().Parent.Name

configs, err := getPbStructForNode(c.Config.Plugins[providerName], context.Selected().Parent)
if err != nil {
return err
}

providerClient, err := c.GetProvider(providerName).PluginClient()
if err != nil {
return err
Expand Down
19 changes: 9 additions & 10 deletions pkg/cmd/plugin/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,8 @@ type ImportCmd struct {

func (cmd *ImportCmd) Run(app *kong.Kong, context *kong.Context, c *cc.CC) error {

providerConfigs, err := getPbStructForNode(context.Selected().Parent)
if err != nil {
return err
}

req := &proto.ExportRequest{
Config: providerConfigs,
}

defaultProviderConfigs, err := getPbStructForNode(context.Path[0].Node())
defaultProviderName := c.GetDefaultProvider().GetName()
defaultProviderConfigs, err := getPbStructForNode(c.Config.Plugins[defaultProviderName], context.Path[0].Node())
if err != nil {
return err
}
Expand All @@ -34,6 +26,13 @@ func (cmd *ImportCmd) Run(app *kong.Kong, context *kong.Context, c *cc.CC) error
includeExt := false

providerName := context.Selected().Parent.Name
providerConfigs, err := getPbStructForNode(c.Config.Plugins[providerName], context.Selected().Parent)
if err != nil {
return err
}
req := &proto.ExportRequest{
Config: providerConfigs,
}

providerClient, err := c.GetProvider(providerName).PluginClient()
if err != nil {
Expand Down
20 changes: 16 additions & 4 deletions pkg/cmd/plugin/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ import (
"google.golang.org/protobuf/types/known/structpb"
)

func getPbStructForNode(node *kong.Node) (*structpb.Struct, error) {
func getPbStructForNode(pluginConfig map[string]interface{}, node *kong.Node) (*structpb.Struct, error) {
cliConfigs := getConfigsForNode(node)

for name, value := range pluginConfig {
if _, ok := cliConfigs[name]; !ok {
cliConfigs[name] = value
}
}

configStruct, err := structpb.NewStruct(cliConfigs)
return configStruct, err
}

func getConfigsForNode(node *kong.Node) map[string]interface{} {
config := make(map[string]interface{})

for _, flag := range node.Flags {
// CLI flags do not have groups
if flag.Group != nil {
if flag.Group != nil && flag.Value.Target.Interface() != flag.DefaultValue.Interface() {
config[flag.Name] = flag.Value.Target.Interface()
}
}
configStruct, err := structpb.NewStruct(config)
return configStruct, err
return config
}
Loading

0 comments on commit 54d6b7f

Please sign in to comment.