Skip to content

Commit

Permalink
DB migration check
Browse files Browse the repository at this point in the history
  • Loading branch information
bsoniam authored and harture committed May 20, 2019
1 parent 0e6f857 commit f62287e
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 35 deletions.
107 changes: 107 additions & 0 deletions cmd/keycloakb/keycloak_bridge.go
Expand Up @@ -7,6 +7,7 @@ import (
"net/http/pprof"
"os"
"os/signal"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -97,6 +98,8 @@ func main() {

// Enabled units
pprofRouteEnabled = c.GetBool("pprof-route-enabled")
auditMigrationEnabled = c.GetBool("db-audit-migration")
configMigrationEnabled = c.GetBool("db-config-migration")

// Influx
influxWriteInterval = c.GetDuration("influx-write-interval")
Expand Down Expand Up @@ -241,6 +244,26 @@ func main() {
logger.Log("msg", "could not create RO DB connection for audit events", "error", err)
return
}

// DB migration version
// checking that the flyway_schema_history has the minimum imposed migration version
// auditevents DB
auditMigrationVersion := c.GetString("db-audit-migration-version")
if auditMigrationEnabled {
// DB schema versioning is enabled
if auditMigrationVersion != "" {
var err error
err = checkMigrationVersion(logger, *auditRwDbParams, eventsRODBConn, auditMigrationVersion)
if err != nil {
return
}
} else {
// DB schema versioning is enabled but no minimum version was given
logger.Log("msg", "Check of DB schema is enabled, but no minimum version provided", "DB", auditRoDbParams.Database)
return
}
}

}

var configurationDBConn database.CloudtrustDB
Expand All @@ -251,6 +274,22 @@ func main() {
logger.Log("msg", "could not create DB connection for configuration storage", "error", err)
return
}
// DB migration version
// cloudtrust_configurations DB
configMigrationVersion := c.GetString("db-config-migration-version")
if configMigrationEnabled {
if configMigrationVersion != "" {
var err error
err = checkMigrationVersion(logger, *configDbParams, configurationDBConn, configMigrationVersion)
if err != nil {
return
}
} else {
// DB schema versioning is enabled but no minimum version was given
logger.Log("msg", "Check of DB schema is enabled, but no minimum version provided", "DB", configDbParams.Database)
return
}
}
}

// Event service.
Expand Down Expand Up @@ -633,6 +672,9 @@ func config(logger log.Logger) *viper.Viper {
//Storage custom configuration in DB
v.SetDefault("config-db", true)
database.ConfigureDbDefault(v, "db-config", "CT_BRIDGE_DB_CONFIG_USERNAME", "CT_BRIDGE_DB_CONFIG_PASSWORD")

v.SetDefault("db-config-migration", false)
v.SetDefault("db-config-migration-version", "")

// Rate limiting (in requests/second)
v.SetDefault("rate-account", 1000)
Expand Down Expand Up @@ -718,6 +760,71 @@ func config(logger log.Logger) *viper.Viper {
return v
}

func checkMigrationVersion(logger log.Logger, dbParams dbConfig, conn events.DBEvents, minMigrationVersion string) error {

var flywayVersion string
row := conn.QueryRow(`SELECT version FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 1;`)
err := row.Scan(&flywayVersion)
if err != nil {
logger.Log("msg", "could not query the flyway_schema_history", "error", err)
return err
}

//flyway version and config migration version must match the format x.y where x and y are integers
matched, err := regexp.MatchString(`^[0-9]+\.[0-9]+$`, minMigrationVersion)
if err != nil {
return err
}
if !matched {
logger.Log("msg", "the config migration version does not match the required format")
return fmt.Errorf("The config migration version does not match the required format")
}

matched, err = regexp.MatchString(`^[0-9]+\.[0-9]+$`, flywayVersion)
if err != nil {
return err
}
if !matched {
logger.Log("msg", "the flyway migration version does not match the required format")
return fmt.Errorf("The flyway migration version does not match the required format")
}

// compare the two versions of the type x.y (major.minor)
minRequiredVersion := strings.Split(minMigrationVersion, ".")
currentFlywayVersion := strings.Split(flywayVersion, ".")

majorRequired, err := strconv.Atoi(minRequiredVersion[0])
if err != nil {
logger.Log("msg", "could not convert majorRequired string to int", "error", err)
return err
}
minorRequired, err := strconv.Atoi(minRequiredVersion[1])
if err != nil {
logger.Log("msg", "could not convert minorRequired string to int", "error", err)
return err
}

majorFlyway, err := strconv.Atoi(currentFlywayVersion[0])
if err != nil {
logger.Log("msg", "could not convert majorFlyway string to int", "error", err)
return err
}
minorFlyway, err := strconv.Atoi(currentFlywayVersion[1])
if err != nil {
logger.Log("msg", "could not convert minorFlyway string to int", "error", err)
return err
}

// it is required for the last script version of the flyway is to be "bigger" than the required version
if (majorFlyway < majorRequired) || (majorFlyway == majorRequired && minorFlyway < minorRequired) {
logger.Log("msg", "the DB schema is not up-to-date", "DB", dbParams.Database)
return fmt.Errorf("DB schema not up-to-date")
}

logger.Log("msg", "DB schema version fits the requirements")
return nil
}

func configureEventsHandler(ComponentName string, ComponentID string, idGenerator idgenerator.IDGenerator, keycloakClient *keycloak.Client, audienceRequired string, tracer tracing.OpentracingClient, logger log.Logger) func(endpoint endpoint.Endpoint) http.Handler {
return func(endpoint endpoint.Endpoint) http.Handler {
var handler http.Handler
Expand Down
5 changes: 5 additions & 0 deletions configs/keycloak_bridge.yml
Expand Up @@ -44,6 +44,9 @@ db-audit-rw-protocol: tcp
db-audit-rw-max-open-conns: 10
db-audit-rw-max-idle-conns: 2
db-audit-rw-conn-max-lifetime: 3600
db-audit-migration: false
db-audit-migration-version:


# DB Audit RO
db-audit-ro-host-port: 127.0.0.1:3306
Expand All @@ -64,6 +67,8 @@ db-config-protocol: tcp
db-config-max-open-conns: 10
db-config-max-idle-conns: 2
db-config-conn-max-lifetime: 3600
db-config-migration: false
db-config-migration-version: 4.1

# audit events
events-db: false
Expand Down
18 changes: 0 additions & 18 deletions pkg/event/module.go
Expand Up @@ -64,24 +64,6 @@ func (sm *statisticModule) Stats(ctx context.Context, m map[string]string) error
}

const (
createTable = `CREATE TABLE IF NOT EXISTS audit (
audit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
audit_time TIMESTAMP NULL,
origin VARCHAR(255),
realm_name VARCHAR(255),
agent_user_id VARCHAR(36),
agent_username VARCHAR(255),
agent_realm_name VARCHAR(255),
user_id VARCHAR(36),
username VARCHAR(255),
ct_event_type VARCHAR(50),
kc_event_type VARCHAR(50),
kc_operation_type VARCHAR(50),
client_id VARCHAR(255),
additional_info TEXT,
CONSTRAINT audit_pk PRIMARY KEY (audit_id)
);`

insertEvent = `INSERT INTO audit (
audit_time,
origin,
Expand Down
8 changes: 0 additions & 8 deletions pkg/export/storage.go
Expand Up @@ -7,11 +7,6 @@ import (
)

const (
createConfigTblStmt = `CREATE TABLE IF NOT EXISTS config (
component_name STRING,
version STRING,
config BYTES,
PRIMARY KEY (component_name, version))`
upsertConfigStmt = `UPSERT INTO config (
component_name,
version,
Expand All @@ -33,9 +28,6 @@ type DB interface {

// NewConfigStorageModule returns the storage module.
func NewConfigStorageModule(db DB) *StorageModule {
// Init DB: create config table.
db.Exec(createConfigTblStmt)

return &StorageModule{
db: db,
}
Expand Down
8 changes: 0 additions & 8 deletions pkg/management/module.go
Expand Up @@ -6,13 +6,6 @@ import (
)

const (
createConfigTableStmt = `CREATE TABLE IF NOT EXISTS realm_configuration(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
realm_id VARCHAR(255) NOT NULL,
configuration JSON,
CHECK (configuration IS NULL OR JSON_VALID(configuration))
);
CREATE UNIQUE INDEX IF NOT EXISTS realm_id_idx ON realm_configuration(realm_id);`
updateConfigStmt = `INSERT INTO realm_configuration (realm_id, configuration)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE configuration = ?;`
Expand All @@ -37,7 +30,6 @@ type configurationDBModule struct {

// NewConfigurationDBModule returns a ConfigurationDB module.
func NewConfigurationDBModule(db DBConfiguration) ConfigurationDBModule {
db.Exec(createConfigTableStmt)
return &configurationDBModule{
db: db,
}
Expand Down
1 change: 0 additions & 1 deletion pkg/management/module_test.go
Expand Up @@ -14,7 +14,6 @@ func TestConfigurationDBModule(t *testing.T) {
defer mockCtrl.Finish()
var mockDB = mock.NewDBConfiguration(mockCtrl)

mockDB.EXPECT().Exec(gomock.Any()).Return(nil, nil).Times(1)
mockDB.EXPECT().Exec(gomock.Any(), "realmId", gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
var configDBModule = NewConfigurationDBModule(mockDB)
var err = configDBModule.StoreOrUpdate(context.Background(), "realmId", "{}")
Expand Down

0 comments on commit f62287e

Please sign in to comment.