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

Refactor setup config #3694

Merged
merged 41 commits into from Jul 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
3a51850
Refactor setup config
nwmac May 27, 2019
5a26673
Fix error logging issues
nwmac May 27, 2019
10c664e
Fixed some typos
richard-cox May 31, 2019
a4553fc
Add initial schema and login method skeletons
kreinecke May 20, 2019
9b9b424
Rename LocalUsers datastore with a unique ID. More code to auth.go
kreinecke May 22, 2019
a304f05
Add last login field to users table. Add unique version string to Reg…
kreinecke May 22, 2019
9323e4b
Added skeleton code for local users repo.
kreinecke May 22, 2019
7b190bb
Add function to find password hash, to local users repository
kreinecke May 22, 2019
a70924c
Add function to add new local user, to local users repository
kreinecke May 22, 2019
00cf310
Add remainder of code for local user login. Fix build.
kreinecke May 23, 2019
8b54416
Code to initialise local users table on startup when a local user is …
kreinecke May 23, 2019
8596a52
Fix incorrect field ordering on new user insert
kreinecke May 23, 2019
3f934c4
Initial auth test function added to test local login
kreinecke May 23, 2019
b3c5582
Fix convey function ordering for several tests
kreinecke May 29, 2019
e35345c
More tests for local login error cases
kreinecke May 29, 2019
d71dd69
Add unit tests for local user auth and creation. Start work on implem…
kreinecke May 30, 2019
ab982d8
Finish tests for adding local user. Finish config of remote/local use…
kreinecke May 31, 2019
7b83ce9
Finish auth login code and associated unit tests. Fix backend tests, …
kreinecke Jun 4, 2019
caee9df
Tidy up and fix lint errors
kreinecke Jun 5, 2019
9e385f5
Change name of env var for local user scope. Modify console output on…
kreinecke Jun 5, 2019
73e28fa
Refactor portalProxy.AddLocalUser and portalProxy.doLocalLogin for Co…
kreinecke Jun 5, 2019
c695fd3
Fix code climate issues
kreinecke Jun 5, 2019
f07878a
Add LocalUser struct to encapsulate attributes of a local user
kreinecke Jun 6, 2019
1870939
Fix ungraceful jetstream crash during config setup if AUTH_ENDPOINT_T…
kreinecke Jun 6, 2019
607221a
Set auth endpoint to local for Travis build/review verification.
kreinecke Jun 7, 2019
a2d1606
Fix skipping local user creation bug
kreinecke Jun 10, 2019
829294c
Codeclimate fix
kreinecke Jun 10, 2019
d558478
backend test fix
kreinecke Jun 10, 2019
4b2d786
push default config for e2e tests
kreinecke Jun 10, 2019
892fb95
Codeclimate fix
kreinecke Jun 10, 2019
2d00baf
Merge remote-tracking branch 'origin/v2-master' into refactor-setup-c…
richard-cox Jun 14, 2019
3fb9d71
Resolve conflicts
kreinecke Jun 17, 2019
036502c
Merge remote-tracking branch 'origin/v2-master' into refactor-setup-c…
nwmac Jun 18, 2019
0c945f5
Address PR feedback. Add initiial unit test
nwmac Jun 18, 2019
d9ef065
Add a few unit tests while we're here
nwmac Jun 19, 2019
e2fb3ba
Merge local auth changes
nwmac Jun 19, 2019
4bc807a
Clean legacy data from old table on migration
nwmac Jun 19, 2019
bb34148
Fixes
nwmac Jun 19, 2019
0411adc
Fix
nwmac Jun 19, 2019
7d8eedd
Merge remote-tracking branch 'origin/v2-master' into refactor-setup2
nwmac Jul 8, 2019
e7fe908
Fix merge issues
nwmac Jul 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/jetstream/datastore/20190621212700_ConfigSchema.go
@@ -0,0 +1,32 @@
package datastore

import (
"database/sql"

"bitbucket.org/liamstask/goose/lib/goose"
)

func init() {
RegisterMigration(20190621212700, "ConfigSchema", func(txn *sql.Tx, conf *goose.DBConf) error {
configTable := "CREATE TABLE IF NOT EXISTS config ("
configTable += " groupName VARCHAR(255) NOT NULL, "
configTable += " name VARCHAR(255) NOT NULL, "
configTable += " value VARCHAR(255) NOT NULL,"
configTable += " last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);"

_, err := txn.Exec(configTable)
if err != nil {
return err
}

// Add a marker to the new table so that later we know we need to migrate the old data to the new table
addMarker := "INSERT INTO config (groupName, name, value) VALUES ('system', '__CONFIG_MIGRATION_NEEDED', 'true')"

_, err = txn.Exec(addMarker)
if err != nil {
return err
}

return nil
})
}
28 changes: 19 additions & 9 deletions src/jetstream/datastore/datastore.go
Expand Up @@ -152,15 +152,31 @@ func GetConnection(dc DatabaseConfig, env *env.VarSet) (*sql.DB, error) {

// GetSQLLiteConnection returns an SQLite DB Connection
func GetSQLLiteConnection(sqliteKeepDB bool) (*sql.DB, error) {
return GetSQLLiteConnectionWithPath(SQLiteDatabaseFile, sqliteKeepDB)
}

// GetSQLLiteConnectionWithPath returns an SQLite DB Connection
func GetSQLLiteConnectionWithPath(databaseFile string, sqliteKeepDB bool) (*sql.DB, error) {
if !sqliteKeepDB {
os.Remove(SQLiteDatabaseFile)
os.Remove(databaseFile)
}

db, err := sql.Open("sqlite3", SQLiteDatabaseFile)
db, err := sql.Open("sqlite3", databaseFile)
if err != nil {
return nil, err
}

conf := CreateFakeSQLiteGooseDriver()
err = ApplyMigrations(conf, db)
if err != nil {
return nil, err
}

return db, nil
}

// CreateFakeSQLiteGooseDriver creates a fake Goose Driver for SQLite
func CreateFakeSQLiteGooseDriver() *goose.DBConf {
// Create fake goose db conf object for SQLite
d := goose.DBDriver{
Name: "sqlite3",
Expand All @@ -171,13 +187,7 @@ func GetSQLLiteConnection(sqliteKeepDB bool) (*sql.DB, error) {
conf := &goose.DBConf{
Driver: d,
}

err = ApplyMigrations(conf, db)
if err != nil {
return nil, err
}

return db, nil
return conf
}

func buildConnectionString(dc DatabaseConfig) string {
Expand Down
14 changes: 10 additions & 4 deletions src/jetstream/datastore/datastore_migrator.go
Expand Up @@ -15,29 +15,35 @@ type StratosMigration func(txn *sql.Tx, conf *goose.DBConf) error

// RegisterMigration registers a migration step. This should be called from an init() function
func RegisterMigration(version int64, name string, f StratosMigration) {
migrationSteps = append(migrationSteps, stratosMigrationStep{
migrationSteps = append(migrationSteps, StratosMigrationStep{
Version: version,
Name: name,
Apply: f,
})
}

type stratosMigrationStep struct {
// StratosMigrationStep represents a migaration step
type StratosMigrationStep struct {
Version int64
Name string
Apply StratosMigration
}

var migrationSteps []stratosMigrationStep
var migrationSteps []StratosMigrationStep

// GetOrderedMigrations returns an order list of migrations to run
func GetOrderedMigrations() []stratosMigrationStep {
func GetOrderedMigrations() []StratosMigrationStep {
sort.Slice(migrationSteps, func(i, j int) bool {
return migrationSteps[i].Version < migrationSteps[j].Version
})
return migrationSteps
}

// SetMigrations replces the current list of migrations - used only by tests internally
func SetMigrations(steps []StratosMigrationStep) {
migrationSteps = steps
}

// ApplyMigrations will perform the migrations
func ApplyMigrations(conf *goose.DBConf, db *sql.DB) error {
current, err := goose.EnsureDBVersion(conf, db)
Expand Down
118 changes: 59 additions & 59 deletions src/jetstream/main.go
Expand Up @@ -84,7 +84,10 @@ func getEnvironmentLookup() *env.VarSet {
// Make environment lookup
envLookup := env.NewVarSet()

// Environment variables directly set trump all others
// Config database store topmost priority
envLookup.AppendSource(console_config.ConfigLookup)

// Environment variables
envLookup.AppendSource(os.LookupEnv)

// If running in CloudFoundry, fallback to a user provided service (if set)
Expand Down Expand Up @@ -144,12 +147,15 @@ func main() {

if isUpgrading {
log.Info("Upgrade in progress (lock file detected) ... waiting for lock file to be removed ...")
start(portalConfig, &portalProxy{env: envLookup}, &setupMiddleware{}, true)
start(portalConfig, &portalProxy{env: envLookup}, false, true)
}
// Grab the Console Version from the executable
portalConfig.ConsoleVersion = appVersion
log.Infof("Stratos Version: %s", portalConfig.ConsoleVersion)

// Initialize an empty config for the console - initially not setup
portalConfig.ConsoleConfig = new(interfaces.ConsoleConfig)

// Initialize the HTTP client
initializeHTTPClients(portalConfig.HTTPClientTimeoutInSecs, portalConfig.HTTPClientTimeoutMutatingInSecs, portalConfig.HTTPConnectionTimeoutInSecs)
log.Info("HTTP client initialized.")
Expand Down Expand Up @@ -242,7 +248,7 @@ func main() {
}()

// Initialise configuration
addSetupMiddleware, err := initialiseConsoleConfiguration(portalProxy)
needSetupMiddleware, err := initialiseConsoleConfiguration(portalProxy)
if err != nil {
log.Infof("Failed to initialise console config due to: %s", err)
return
Expand Down Expand Up @@ -274,7 +280,7 @@ func main() {
portalProxy.StoreDiagnostics()

// Start the back-end
if err := start(portalProxy.Config, portalProxy, addSetupMiddleware, false); err != nil {
if err := start(portalProxy.Config, portalProxy, needSetupMiddleware, false); err != nil {
log.Fatalf("Unable to start: %v", err)
}
log.Info("Unable to start Stratos JetStream backend")
Expand All @@ -292,79 +298,74 @@ func (portalProxy *portalProxy) GetPlugin(name string) interface{} {
return plugin
}

func initialiseConsoleConfiguration(portalProxy *portalProxy) (*setupMiddleware, error) {
func initialiseConsoleConfiguration(portalProxy *portalProxy) (bool, error) {

addSetupMiddleware := new(setupMiddleware)
addSetupMiddleware := false
consoleRepo, err := console_config.NewPostgresConsoleConfigRepository(portalProxy.DatabaseConnectionPool)
if err != nil {
log.Errorf("Unable to intialise Stratos backend config due to: %+v", err)
log.Errorf("Unable to initialize Stratos backend config due to: %+v", err)
return addSetupMiddleware, err
}
isInitialised, err := consoleRepo.IsInitialised()

if err != nil || !isInitialised {
// Exception occurred when trying to determine
// if its initialised or instance isn't initialised,
// will attempt to initialise it from the env vars.

consoleConfig, err := portalProxy.initialiseConsoleConfig(consoleRepo)
if err != nil {
log.Warnf("Failed to initialise Stratos config due to: %+v", err)
// Do this BEFORE we load the config from the database, so env var lookup at this stage
// looks at environment variables etc but NOT the database
// Migrate data from old setup table to new config table (if needed)
err = console_config.MigrateSetupData(portalProxy, consoleRepo)
if err != nil {
log.Warnf("Unable to initialize config environment provider: %+v", err)
}

addSetupMiddleware.addSetup = true
addSetupMiddleware.consoleRepo = consoleRepo
log.Info("Will add `setup` route and middleware")
// Load config stored in the database
err = console_config.InitializeConfEnvProvider(consoleRepo)
if err != nil {
log.Warnf("Unable to load configuration from database: %+v", err)
}

} else {
showStratosConfig(consoleConfig)
portalProxy.Config.ConsoleConfig = consoleConfig
setSSOFromConfig(portalProxy, consoleConfig)
}
// Now that the config DB is an env provider, we can just use the env to fetch the setup values
consoleConfig, err := portalProxy.initialiseConsoleConfig(portalProxy.Env())
if err != nil {
// Could not read config - this should not happen - so abort if it does
log.Fatalf("Unable to load console config; %+v", err)
}

} else if err == nil && isInitialised {
consoleConfig, err := consoleRepo.GetConsoleConfig()
if err != nil {
log.Infof("Instance is initialised, but console_config table may contain junk data! %+v", err)
}
// We dynamically determine if we need to enter setup mode based on the configuration
// We need: UAA Endpoint and Console Admin Scope
if !consoleConfig.IsSetupComplete() {
addSetupMiddleware = true
log.Info("Will add `setup` route and middleware")
} else {
showStratosConfig(consoleConfig)
portalProxy.Config.ConsoleConfig = consoleConfig
setSSOFromConfig(portalProxy, consoleConfig)
portalProxy.Config.SSOLogin = consoleConfig.UseSSO
}

return addSetupMiddleware, nil
}

func setSSOFromConfig(portalProxy *portalProxy, configuration *interfaces.ConsoleConfig) {
// For SSO, override the value loaded from the config file, so that this is what we use
if !portalProxy.Env().IsSet("SSO_LOGIN") {
portalProxy.Config.SSOLogin = configuration.UseSSO
}
}

func showStratosConfig(config *interfaces.ConsoleConfig) {
log.Infof("Stratos is intialised with the following setup:")
log.Infof("... Auth Endpoint Type : %s", config.AuthEndpointType)
log.Infof("Stratos is initialized with the following setup:")
log.Infof("... Auth Endpoint Type : %s", config.AuthEndpointType)
if val, found := interfaces.AuthEndpointTypes[config.AuthEndpointType]; found {
if val == interfaces.Local {
log.Infof("... Local User : %s", config.LocalUser)
log.Infof("... Local User Scope : %s", config.LocalUserScope)
log.Infof("... Local User : %s", config.LocalUser)
log.Infof("... Local User Scope : %s", config.LocalUserScope)
} else { //Auth type is set to remote
log.Infof("... UAA Endpoint : %s", config.UAAEndpoint)
log.Infof("... Authorization Endpoint : %s", config.AuthorizationEndpoint)
log.Infof("... Console Client : %s", config.ConsoleClient)
log.Infof("... Admin Scope : %s", config.ConsoleAdminScope)
log.Infof("... Use SSO Login : %t", config.UseSSO)
}
}
log.Infof("... Skip SSL Validation : %t", config.SkipSSLValidation)
log.Infof("... Setup Complete : %t", config.IsSetupComplete)
log.Infof("... UAA Endpoint : %s", config.UAAEndpoint)
log.Infof("... Authorization Endpoint : %s", config.AuthorizationEndpoint)
log.Infof("... Console Client : %s", config.ConsoleClient)
log.Infof("... Admin Scope : %s", config.ConsoleAdminScope)
log.Infof("... Use SSO Login : %t", config.UseSSO)
}
}
log.Infof("... Skip SSL Validation : %t", config.SkipSSLValidation)
log.Infof("... Setup Complete : %t", config.IsSetupComplete())
}

func showSSOConfig(portalProxy *portalProxy) {
// Show SSO Configuration
log.Infof("SSO Configuration:")
log.Infof("... SSO Enabled : %t", portalProxy.Config.SSOLogin)
log.Infof("... SSO Options : %s", portalProxy.Config.SSOOptions)
log.Infof("... SSO Enabled : %t", portalProxy.Config.SSOLogin)
log.Infof("... SSO Options : %s", portalProxy.Config.SSOOptions)
}

func getEncryptionKey(pc interfaces.PortalConfig) ([]byte, error) {
Expand Down Expand Up @@ -641,7 +642,7 @@ func initializeHTTPClients(timeout int64, timeoutMutating int64, connectionTimeo
httpClientMutatingSkipSSL.Timeout = time.Duration(timeoutMutating) * time.Second
}

func start(config interfaces.PortalConfig, p *portalProxy, addSetupMiddleware *setupMiddleware, isUpgrade bool) error {
func start(config interfaces.PortalConfig, p *portalProxy, needSetupMiddleware bool, isUpgrade bool) error {
log.Debug("start")
e := echo.New()
e.HideBanner = true
Expand Down Expand Up @@ -674,7 +675,7 @@ func start(config interfaces.PortalConfig, p *portalProxy, addSetupMiddleware *s
e.Use(bindToEnv(retryAfterUpgradeMiddleware, p.Env()))

if !isUpgrade {
p.registerRoutes(e, addSetupMiddleware)
p.registerRoutes(e, needSetupMiddleware)
}

if isUpgrade {
Expand All @@ -698,7 +699,7 @@ func start(config interfaces.PortalConfig, p *portalProxy, addSetupMiddleware *s
if engineErr != nil {
engineErrStr := fmt.Sprintf("%s", engineErr)
if !strings.Contains(engineErrStr, "Server closed") {
log.Warnf("Failed to start HTTP/S server: %v+", engineErr)
log.Warnf("Failed to start HTTP/S server: %+v", engineErr)
}
}

Expand Down Expand Up @@ -750,7 +751,7 @@ func (p *portalProxy) getHttpClient(skipSSLValidation bool, mutating bool) http.
return client
}

func (p *portalProxy) registerRoutes(e *echo.Echo, addSetupMiddleware *setupMiddleware) {
func (p *portalProxy) registerRoutes(e *echo.Echo, needSetupMiddleware bool) {
log.Debug("registerRoutes")

for _, plugin := range p.Plugins {
Expand All @@ -770,9 +771,8 @@ func (p *portalProxy) registerRoutes(e *echo.Echo, addSetupMiddleware *setupMidd
pp.Use(p.setSecureCacheContentMiddleware)

// Add middleware to block requests if unconfigured
if addSetupMiddleware.addSetup {
go p.SetupPoller(addSetupMiddleware)
e.Use(p.SetupMiddleware(addSetupMiddleware))
if needSetupMiddleware {
e.Use(p.SetupMiddleware())
pp.POST("/v1/setup", p.setupConsole)
pp.POST("/v1/setup/update", p.setupConsoleUpdate)
}
Expand Down
4 changes: 2 additions & 2 deletions src/jetstream/plugins/cfappssh/app_ssh.go
Expand Up @@ -162,7 +162,7 @@ func (cfAppSsh *CFAppSSH) appSSH(c echo.Context) error {
_, r, err := ws.ReadMessage()
if err != nil {
log.Error("Error reading message from web socket")
log.Warnf("%v+", err)
log.Warnf("%+v", err)
return err
}

Expand Down Expand Up @@ -293,7 +293,7 @@ func getSSHCode(authorizeEndpoint, clientID, token string, skipSSLValidation boo

resp, err := httpClientWithoutRedirects.Do(authorizeReq)
if resp != nil {
log.Infof("%v+", resp)
log.Infof("%+v", resp)
}
if err == nil {
return "", errors.New("Authorization server did not redirect with one time code")
Expand Down