mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-09 00:00:00 +01:00
237 lines
9.8 KiB
Go
237 lines
9.8 KiB
Go
/**
|
|
* This file is part of VILLASweb-backend-go
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*********************************************************************************/
|
|
|
|
package configuration
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"github.com/zpatrick/go-config"
|
|
)
|
|
|
|
// Global configuration
|
|
var GlobalConfig *config.Config = nil
|
|
|
|
type GroupedScenario struct {
|
|
Scenario int `yaml:"scenario"`
|
|
Duplicate bool `default:"false" yaml:"duplicate"`
|
|
}
|
|
|
|
var ScenarioGroupMap = map[string][]GroupedScenario{}
|
|
|
|
func InitConfig() error {
|
|
if GlobalConfig != nil {
|
|
return nil
|
|
}
|
|
|
|
var (
|
|
dbHost = flag.String("db-host", "/var/run/postgresql", "Host of the PostgreSQL database (default is /var/run/postgresql for localhost DB on Ubuntu systems)")
|
|
dbPort = flag.Int("db-port", -1, "Port of the PostgreSQL server")
|
|
dbName = flag.String("db-name", "villasdb", "Name of the database to use (default is villasdb)")
|
|
dbUser = flag.String("db-user", "", "Username of database connection (default is <empty>)")
|
|
dbPass = flag.String("db-pass", "", "Password of database connection (default is <empty>)")
|
|
dbSSLMode = flag.String("db-ssl-mode", "disable", "SSL mode of DB (default is disable)") // TODO: change default for production
|
|
dbClear = flag.Bool("db-clear", false, "Set to true if you want to clear all DB tables upon startup. This parameter has to be used with great care, its effects cannot be reverted.")
|
|
amqpHost = flag.String("amqp-host", "", "If set, use this as host for AMQP broker (default is disabled)")
|
|
amqpUser = flag.String("amqp-user", "", "Username for AMQP broker")
|
|
amqpPass = flag.String("amqp-pass", "", "Password for AMQP broker")
|
|
configFile = flag.String("config", "", "Path to YAML configuration file")
|
|
port = flag.String("port", "4000", "Port of the backend (default is 4000)")
|
|
adminUser = flag.String("admin-user", "", "Initial admin username")
|
|
adminPass = flag.String("admin-pass", "", "Initial admin password")
|
|
adminMail = flag.String("admin-mail", "", "Initial admin mail address")
|
|
s3Bucket = flag.String("s3-bucket", "", "S3 Bucket for uploading files")
|
|
s3Endpoint = flag.String("s3-endpoint", "", "Endpoint of S3 API for file uploads")
|
|
s3EndpointPublic = flag.String("s3-endpoint-public", "", "Public endpoint address of S3 API for file uploads")
|
|
s3Region = flag.String("s3-region", "default", "S3 Region for file uploads")
|
|
s3NoSSL = flag.Bool("s3-nossl", false, "Use encrypted connections to the S3 API")
|
|
s3PathStyle = flag.Bool("s3-pathstyle", false, "Use path-style S3 API")
|
|
jwtSecret = flag.String("jwt-secret", "This should NOT be here!!@33$8&", "The JSON Web Token secret")
|
|
jwtExpiresAfter = flag.String("jwt-expires-after", "168h" /* 1 week */, "The time after which the JSON Web Token expires")
|
|
authExternal = flag.Bool("auth-external", false, "Use external authentication via X-Forwarded-User header (e.g. OAuth2 Proxy)")
|
|
authExternalLoginURL = flag.String("auth-external-login-url", "/oauth2/start", "A URL to initiate external login procedure")
|
|
authExternalProviderName = flag.String("auth-external-provider-name", "JupyterHub", "A name of the external authentication provider")
|
|
authLogoutURL = flag.String("auth-logout-url", "/oauth2/sign_out?rd=https%3A%2F%2Fjupyter.k8s.eonerc.rwth-aachen.de%2Fhub%2Flogout", "The URL to redirect the user to log out")
|
|
title = flag.String("title", "VILLASweb", "Title shown in the frontend")
|
|
subTitle = flag.String("sub-title", "", "Sub-title shown in the frontend")
|
|
contactName = flag.String("contact-name", "Steffen Vogel", "Name of the administrative contact")
|
|
contactMail = flag.String("contact-mail", "svogel2@eonerc.rwth-aachen.de", "EMail of the administrative contact")
|
|
testDataPath = flag.String("test-data-path", "", "The path to a test data json file")
|
|
groupsPath = flag.String("groups-path", "", "The path to a YAML file that maps user groups to scenario IDs")
|
|
apiUpdateInterval = flag.String("api-update-interval", "10s" /* 10 sec */, "Interval in which API URL is queried for status updates of ICs")
|
|
k8sRancherURL = flag.String("k8s-rancher-url", "https://rancher.k8s.eonerc.rwth-aachen.de", "URL of Rancher instance that is used to deploy the backend")
|
|
k8sClusterName = flag.String("k8s-cluster-name", "local", "Name of the Kubernetes cluster where the backend is deployed")
|
|
staleICTime = flag.String("stale-ic-time", "1h" /* 1 hour */, "Time after which an IC is considered stale")
|
|
webRTCiceUrls = flag.String("webrtc-ice-urls",
|
|
"stun:stun.l.google.com:19302,villas:villas@stun:stun.0l.de,villas:villas@turn:turn.0l.de?transport=udp,villas:villas@turn:turn.0l.de?transport=tcp",
|
|
"WebRTC ICE URLs (comma-separated list, use username:password@url style for non-anonymous URLs)")
|
|
)
|
|
flag.Parse()
|
|
|
|
static := map[string]string{
|
|
"db.host": *dbHost,
|
|
"db.port": fmt.Sprint(*dbPort),
|
|
"db.name": *dbName,
|
|
"db.user": *dbUser,
|
|
"db.pass": *dbPass,
|
|
"db.ssl": *dbSSLMode,
|
|
"amqp.host": *amqpHost,
|
|
"amqp.user": *amqpUser,
|
|
"amqp.pass": *amqpPass,
|
|
"port": *port,
|
|
"admin.user": *adminUser,
|
|
"admin.pass": *adminPass,
|
|
"admin.mail": *adminMail,
|
|
"s3.bucket": *s3Bucket,
|
|
"s3.endpoint": *s3Endpoint,
|
|
"s3.endpoint-public": *s3EndpointPublic,
|
|
"s3.region": *s3Region,
|
|
"jwt.secret": *jwtSecret,
|
|
"jwt.expires-after": *jwtExpiresAfter,
|
|
"auth.external.login-url": *authExternalLoginURL,
|
|
"auth.external.provider-name": *authExternalProviderName,
|
|
"auth.logout-url": *authLogoutURL,
|
|
"title": *title,
|
|
"sub-title": *subTitle,
|
|
"contact.name": *contactName,
|
|
"contact.mail": *contactMail,
|
|
"test.datapath": *testDataPath,
|
|
"groups.path": *groupsPath,
|
|
"config.file": *configFile,
|
|
"apiupdateinterval": *apiUpdateInterval,
|
|
"k8s.rancher-url": *k8sRancherURL,
|
|
"k8s.cluster-name": *k8sClusterName,
|
|
"staleictime": *staleICTime,
|
|
"webrtc.ice-urls": *webRTCiceUrls,
|
|
}
|
|
|
|
if *dbClear {
|
|
static["db.clear"] = "true"
|
|
} else {
|
|
static["db.clear"] = "false"
|
|
}
|
|
|
|
if *s3NoSSL {
|
|
static["s3.nossl"] = "true"
|
|
} else {
|
|
static["s3.nossl"] = "false"
|
|
}
|
|
|
|
if *s3PathStyle {
|
|
static["s3.pathstyle"] = "true"
|
|
} else {
|
|
static["s3.pathstyle"] = "false"
|
|
}
|
|
|
|
if *authExternal {
|
|
static["auth.external.enabled"] = "true"
|
|
} else {
|
|
static["auth.external.enabled"] = "false"
|
|
}
|
|
|
|
mappings := map[string]string{}
|
|
for name := range static {
|
|
envName := strings.ReplaceAll(name, ".", "_")
|
|
envName = strings.ReplaceAll(envName, "-", "_")
|
|
envName = strings.ToUpper(envName)
|
|
|
|
mappings[envName] = name
|
|
}
|
|
|
|
defaults := config.NewStatic(static)
|
|
env := config.NewEnvironment(mappings)
|
|
|
|
if _, err := os.Stat(*configFile); os.IsNotExist(err) {
|
|
GlobalConfig = config.NewConfig([]config.Provider{defaults, env})
|
|
} else {
|
|
yamlFile := config.NewYAMLFile(*configFile)
|
|
GlobalConfig = config.NewConfig([]config.Provider{defaults, yamlFile, env})
|
|
}
|
|
|
|
err := GlobalConfig.Load()
|
|
if err != nil {
|
|
log.Fatal("failed to parse config")
|
|
return err
|
|
}
|
|
|
|
settings, _ := GlobalConfig.Settings()
|
|
|
|
keys := make([]string, 0, len(settings))
|
|
for k := range settings {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
log.Print("All settings (except for PW and secrets):")
|
|
for _, k := range keys {
|
|
if !strings.Contains(k, "pass") && !strings.Contains(k, "secret") {
|
|
log.Printf(" %s = %s \n", k, settings[k])
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func remove(arr []GroupedScenario, index int) []GroupedScenario {
|
|
arr[index] = arr[len(arr)-1]
|
|
return arr[:len(arr)-1]
|
|
}
|
|
|
|
func ReadGroupsFile(path string) error {
|
|
|
|
_, err := os.Stat(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
yamlFile, err := os.Open(path)
|
|
if err != nil {
|
|
return fmt.Errorf("error opening yaml file for groups: %v", err)
|
|
}
|
|
log.Println("Successfully opened yaml groups file", path)
|
|
|
|
defer yamlFile.Close()
|
|
|
|
byteValue, _ := ioutil.ReadAll(yamlFile)
|
|
|
|
err = yaml.Unmarshal(byteValue, &ScenarioGroupMap)
|
|
if err != nil {
|
|
return fmt.Errorf("error unmarshalling yaml into ScenarioGroupMap: %v", err)
|
|
}
|
|
|
|
for _, group := range ScenarioGroupMap {
|
|
for i, scenario := range group {
|
|
// remove invalid values that might have been introduced by typos
|
|
// (Unmarshal sets default values when it doesn't find a field)
|
|
if scenario.Scenario == 0 {
|
|
log.Println("Removing entry from ScenarioGroupMap, check for typos in the yaml!")
|
|
remove(group, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Println("ScenarioGroupMap", ScenarioGroupMap)
|
|
|
|
return nil
|
|
}
|