peridot/utils/flags.go

149 lines
4.8 KiB
Go

// Copyright (c) All respective contributors to the Peridot Project. All rights reserved.
// Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved.
// Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package utils
import (
"fmt"
"math/rand"
"net/url"
"os"
"strconv"
"strings"
"time"
"peridot.resf.org/servicecatalog"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
// FlagConfig is some extra customization options
// for Cobra flags
type FlagConfig struct {
Name string
DefaultPort int
DatabaseName *string
}
// NewFlagConfig returns a default FlagConfig
func NewFlagConfig() *FlagConfig {
return &FlagConfig{
DefaultPort: 8080,
}
}
func defaultEnv(env string, def string) string {
if e := os.Getenv(env); e != "" {
return e
}
return def
}
func AddDBFlagsOnly(f *pflag.FlagSet, config *FlagConfig) {
dname := ""
if config.DatabaseName != nil {
dname = *config.DatabaseName
}
// Default is dev only
f.String("database.url", fmt.Sprintf("postgresql://postgres:postgres@127.0.0.1:%s/%sdev?sslmode=disable", defaultEnv("POSTGRES_PORT", "5432"), dname), "Database host")
}
// AddFlags add the default flags to the cmd of a grpc service
func AddFlags(f *pflag.FlagSet, config *FlagConfig) {
defaultPort := config.DefaultPort
if envPort := os.Getenv("PORT"); envPort != "" {
envNumPort, err := strconv.Atoi(envPort)
if err != nil {
logrus.Fatalf("could not use PORT, err: %s", err)
}
defaultPort = envNumPort
}
config.DefaultPort = defaultPort
issuer := "https://hdr.build.resf.org/"
jwks := fmt.Sprintf("%s/.well-known/jwks.json", servicecatalog.HydraPublic())
if os.Getenv("RESF_ENV") == "" || (os.Getenv("RESF_ENV") == "dev" && os.Getenv("LOCALSTACK_ENDPOINT") != "") {
issuer = "https://hdr-dev.internal.pdev.resf.localhost/"
} else if os.Getenv("RESF_ENV") != "prod" {
issuer = fmt.Sprintf("https://hdr-%s.internal.build.resf.org/", os.Getenv("RESF_ENV"))
}
f.String("oidc.issuer", issuer, "OpenID Connect Issuer for the authentication interceptor")
f.String("oidc.jwks", jwks, "OpenID Connect JWKs for the authentication interceptor")
f.String("api.port", strconv.Itoa(defaultPort), "Port to serve the REST service on")
f.String("grpc.port", strconv.Itoa(defaultPort+1), "Port to serve the gRPC service on")
AddDBFlagsOnly(f, config)
f.Bool("production", false, "Enable production mode")
BindOnly(f, config)
}
// BindOnly only binds the given flags to viper opposed to AddFlags
// which also adds flags
func BindOnly(f *pflag.FlagSet, config *FlagConfig) {
name := config.Name
if name == "" {
name = "PERIDOT"
}
viper.SetEnvPrefix(name)
viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
err := viper.BindPFlags(f)
if err != nil {
logrus.Fatalf("could not bind flags to viper - %s", err)
}
}
// Main is common actions that should be executed in main
func Main() {
rand.Seed(time.Now().Unix())
if dbURL := viper.GetString("database.url"); strings.Contains(dbURL, "REPLACEME") {
escapedPassword := url.QueryEscape(os.Getenv("DATABASE_PASSWORD"))
viper.Set("database.url", strings.Replace(dbURL, "REPLACEME", escapedPassword, 1))
}
if !viper.GetBool("production") {
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.Infoln("production mode activated")
}
}