Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "nodes" plugin for generating config files #18

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions cmd/generate.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build client || all
// +build client all
///go:build client || all
/// +build client all

package cmd

Expand All @@ -20,6 +20,7 @@ var (
tokenFetchRetries int
templatePaths []string
pluginPath string
pluginArgs map[string]string
cacertPath string
useCompression bool
)
Expand Down Expand Up @@ -61,13 +62,14 @@ var generateCmd = &cobra.Command{
RunTargets(&config, args, targets...)
} else {
if pluginPath == "" {
fmt.Printf("no plugin path specified")
log.Error().Msg("no plugin path specified")
return
}

// run generator.Generate() with just plugin path and templates provided
generator.Generate(&config, generator.Params{
PluginPath: pluginPath,
PluginArgs: pluginArgs,
TemplatePaths: templatePaths,
})

Expand All @@ -86,6 +88,8 @@ func RunTargets(config *configurator.Config, args []string, targets ...string) {
for _, target := range targets {
outputBytes, err := generator.GenerateWithTarget(config, generator.Params{
Args: args,
Host: remoteHost,
Port: remotePort,
PluginPath: pluginPath,
Target: target,
Verbose: verbose,
Expand Down Expand Up @@ -122,9 +126,10 @@ func RunTargets(config *configurator.Config, args []string, targets ...string) {
}
log.Info().Msgf("wrote file to '%s'\n", outputPath)
}
} else if outputPath != "" && targetCount > 1 && useCompression {
} else if outputPath != "" && len(outputBytes) > 1 && useCompression {
// write multiple files to archive, compress, then save to output path
out, err := os.Create(fmt.Sprintf("%s.tar.gz", outputPath))
outputPath = fmt.Sprintf("%s.tar.gz", outputPath)
out, err := os.Create(outputPath)
if err != nil {
log.Error().Err(err).Msg("failed to write archive")
os.Exit(1)
Expand All @@ -140,7 +145,7 @@ func RunTargets(config *configurator.Config, args []string, targets ...string) {
log.Error().Err(err).Msg("failed to create archive")
os.Exit(1)
}

log.Info().Msgf("wrote file to '%s'\n", outputPath)
} else if outputPath != "" && targetCount > 1 || templateCount > 1 {
// write multiple files in directory using template name
err := os.MkdirAll(filepath.Clean(outputPath), 0o755)
Expand Down Expand Up @@ -174,6 +179,7 @@ func init() {
generateCmd.Flags().StringSliceVar(&targets, "target", []string{}, "set the targets to run pre-defined config")
generateCmd.Flags().StringSliceVar(&templatePaths, "template", []string{}, "set the paths for the Jinja 2 templates to use")
generateCmd.Flags().StringVar(&pluginPath, "plugin", "", "set the generator plugin path")
generateCmd.Flags().StringToStringVar(&pluginArgs, "plugin-args", map[string]string{}, "set the generate plugin args as key-value pairs")
generateCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets")
generateCmd.Flags().StringVar(&cacertPath, "cacert", "", "path to CA cert. (defaults to system CAs)")
generateCmd.Flags().IntVar(&tokenFetchRetries, "fetch-retries", 5, "set the number of retries to fetch an access token")
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ require (
github.com/OpenCHAMI/jwtauth/v5 v5.0.0-20240321222802-e6cb468a2a18
github.com/go-chi/chi/v5 v5.1.0
github.com/lestrrat-go/jwx/v2 v2.1.1
github.com/mitchellh/mapstructure v1.5.0
github.com/nikolalohinski/gonja/v2 v2.2.0
github.com/openchami/chi-middleware/auth v0.0.0-20240812224658-b16b83c70700
github.com/openchami/chi-middleware/log v0.0.0-20240812224658-b16b83c70700
github.com/rodaine/table v1.2.0
github.com/rs/zerolog v1.33.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -35,6 +35,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/sys v0.22.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
74 changes: 53 additions & 21 deletions pkg/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,25 @@ func NewSmdClient(opts ...ClientOption) SmdClient {
return client
}

func WithHost(host string) ClientOption {
func WithClientHost(host string) ClientOption {
return func(c *SmdClient) {
c.Host = host
}
}

func WithPort(port int) ClientOption {
func WithClientPort(port int) ClientOption {
return func(c *SmdClient) {
c.Port = port
}
}

func WithAccessToken(token string) ClientOption {
func WithClientAccessToken(token string) ClientOption {
return func(c *SmdClient) {
c.AccessToken = token
}
}

func WithCertPool(certPool *x509.CertPool) ClientOption {
func WithClientCertPool(certPool *x509.CertPool) ClientOption {
return func(c *SmdClient) {
c.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
Expand All @@ -82,13 +82,7 @@ func WithCertPoolFile(certPath string) ClientOption {
cacert, _ := os.ReadFile(certPath)
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(cacert)
return WithCertPool(certPool)
}

func WithVerbosity() util.Option {
return func(p util.Params) {
p["verbose"] = true
}
return WithClientCertPool(certPool)
}

// Create a set of params with all default values.
Expand All @@ -98,16 +92,56 @@ func NewParams() util.Params {
}
}

// Fetch the ethernet interfaces from SMD service using its API. An access token may be required if the SMD
// service SMD_JWKS_URL envirnoment variable is set.
func WithNetwork(network string) util.Option {
return func(p util.Params) {
p["network"] = network
}
}

func WithIPAddress(ipAddr string) util.Option {
return func(p util.Params) {
p["ip"] = ipAddr
}
}

func GetNetwork(p util.Params) string {
if network, ok := p["network"].(string); ok {
return network
}

// default value
return ""
}

func GetIPAddress(p util.Params) string {
if ip, ok := p["ip"].(string); ok {
return ip
}

// default value
return ""
}

// Fetch the ethernet interfaces from SMD service using its API. An access token
// may be required if the SMD service SMD_JWKS_URL envirnoment variable is set.
//
// TODO: Change the `Option` type being used here to reduce it's scope.
func (client *SmdClient) FetchEthernetInterfaces(opts ...util.Option) ([]EthernetInterface, error) {
var (
params = util.ToDict(opts...)
verbose = util.Get[bool](params, "verbose")
eths = []EthernetInterface{}
params = util.ToDict(opts...)
verbose = util.GetVerbose(params)
network = GetNetwork(params)
eths = []EthernetInterface{}
endpoint = "/Inventory/EthernetInterfaces"
)

// add network to endpoint fetch filter by network type
if network != "" {
endpoint = fmt.Sprintf("%s?Network=%s", endpoint, network)
}

// make request to SMD endpoint
b, err := client.makeRequest("/Inventory/EthernetInterfaces")
b, err := client.makeRequest(endpoint)
if err != nil {
return nil, fmt.Errorf("failed to read HTTP response: %v", err)
}
Expand All @@ -119,10 +153,8 @@ func (client *SmdClient) FetchEthernetInterfaces(opts ...util.Option) ([]Etherne
}

// print what we got if verbose is set
if verbose != nil {
if *verbose {
fmt.Printf("Ethernet Interfaces: %v\n", string(b))
}
if verbose {
fmt.Printf("Ethernet Interfaces: %v\n", string(b))
}

return eths, nil
Expand Down
Loading