Commit c16e3b5a authored by Bobby Rullo's avatar Bobby Rullo

db: add DB migration code and scripts.

parent abaf76a0
...@@ -3,6 +3,21 @@ ...@@ -3,6 +3,21 @@
export GOPATH=${PWD}/Godeps/_workspace export GOPATH=${PWD}/Godeps/_workspace
export GOBIN=${PWD}/bin export GOBIN=${PWD}/bin
if command -v go-bindata &>/dev/null; then
DEX_MIGRATE_FROM_DISK=${DEX_MIGRATE_FROM_DISK:=false}
echo "Turning migrations into ./db/migrations/assets.go"
if [ "$DEX_MIGRATE_FROM_DISK" = true ]; then
echo "Compiling migrations.go: will read migrations from disk."
else
echo "Compiling migrations into migrations.go"
fi
go-bindata -debug=$DEX_MIGRATE_FROM_DISK -modtime=1 -pkg migrations -o ./db/migrations/assets.go ./db/migrations
gofmt -w ./db/migrations/assets.go
else
echo "Could not find go-bindata in path, will not generate migrations"
fi
rm -rf $GOPATH/src/github.com/coreos/dex rm -rf $GOPATH/src/github.com/coreos/dex
mkdir -p $GOPATH/src/github.com/coreos/ mkdir -p $GOPATH/src/github.com/coreos/
ln -s ${PWD} $GOPATH/src/github.com/coreos/dex ln -s ${PWD} $GOPATH/src/github.com/coreos/dex
......
...@@ -66,7 +66,7 @@ type clientIdentityModel struct { ...@@ -66,7 +66,7 @@ type clientIdentityModel struct {
ID string `db:"id"` ID string `db:"id"`
Secret []byte `db:"secret"` Secret []byte `db:"secret"`
Metadata string `db:"metadata"` Metadata string `db:"metadata"`
DexAdmin bool `db:"dexAdmin"` DexAdmin bool `db:"dex_admin"`
} }
func newClientMetadataJSON(cm *oidc.ClientMetadata) *clientMetadataJSON { func newClientMetadataJSON(cm *oidc.ClientMetadata) *clientMetadataJSON {
......
package db
import (
"fmt"
"github.com/coopernurse/gorp"
"github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate"
"github.com/coreos/dex/db/migrations"
)
const (
migrationDialect = "postgres"
migrationTable = "dex_migrations"
migrationDir = "db/migrations"
)
func init() {
migrate.SetTable(migrationTable)
}
func MigrateToLatest(dbMap *gorp.DbMap) (int, error) {
source := getSource()
return migrate.Exec(dbMap.Db, migrationDialect, source, migrate.Up)
}
func MigrateMaxMigrations(dbMap *gorp.DbMap, max int) (int, error) {
source := getSource()
return migrate.ExecMax(dbMap.Db, migrationDialect, source, migrate.Up, max)
}
func GetPlannedMigrations(dbMap *gorp.DbMap) ([]*migrate.PlannedMigration, error) {
migrations, _, err := migrate.PlanMigration(dbMap.Db, migrationDialect, getSource(), migrate.Up, 0)
return migrations, err
}
func DropMigrationsTable(dbMap *gorp.DbMap) error {
qt := pq.QuoteIdentifier(migrationTable)
_, err := dbMap.Exec(fmt.Sprintf("drop table if exists %s ;", qt))
return err
}
func getSource() migrate.MigrationSource {
return &migrate.AssetMigrationSource{
Dir: migrationDir,
Asset: migrations.Asset,
AssetDir: migrations.AssetDir,
}
}
package db
import (
"fmt"
"os"
"testing"
"github.com/coopernurse/gorp"
)
func initDB(dsn string) *gorp.DbMap {
c, err := NewConnection(Config{DSN: dsn})
if err != nil {
panic(fmt.Sprintf("error making db connection: %q", err))
}
if err = c.DropTablesIfExists(); err != nil {
panic(fmt.Sprintf("Unable to drop database tables: %v", err))
}
return c
}
// TestGetPlannedMigrations is a sanity check, ensuring that at least one
// migration can be found.
func TestGetPlannedMigrations(t *testing.T) {
dsn := os.Getenv("DEX_TEST_DSN")
if dsn == "" {
t.Logf("Test will not run without DEX_TEST_DSN environment variable.")
return
}
dbMap := initDB(dsn)
ms, err := GetPlannedMigrations(dbMap)
if err != nil {
pwd, err := os.Getwd()
t.Logf("pwd: %v", pwd)
t.Fatalf("unexpected err: %q", err)
}
if len(ms) == 0 {
t.Fatalf("expected non-empty migrations")
}
}
-- +migrate Up
CREATE TABLE IF NOT EXISTS "authd_user" (
"id" text not null primary key,
"email" text,
"email_verified" boolean,
"display_name" text,
"admin" boolean) ;
CREATE TABLE IF NOT EXISTS "client_identity" (
"id" text not null primary key,
"secret" bytea,
"metadata" text);
CREATE TABLE IF NOT EXISTS "connector_config" (
"id" text not null primary key,
"type" text, "config" text) ;
CREATE TABLE IF NOT EXISTS "key" (
"value" bytea not null primary key) ;
CREATE TABLE IF NOT EXISTS "password_info" (
"user_id" text not null primary key,
"password" text,
"password_expires" bigint) ;
CREATE TABLE IF NOT EXISTS "session" (
"id" text not null primary key,
"state" text,
"created_at" bigint,
"expires_at" bigint,
"client_id" text,
"client_state" text,
"redirect_url" text, "identity" text,
"connector_id" text,
"user_id" text, "register" boolean) ;
CREATE TABLE IF NOT EXISTS "session_key" (
"key" text not null primary key,
"session_id" text,
"expires_at" bigint,
"stale" boolean) ;
CREATE TABLE IF NOT EXISTS "remote_identity_mapping" (
"connector_id" text not null,
"user_id" text,
"remote_id" text not null,
primary key ("connector_id", "remote_id")) ;
-- +migrate Up
ALTER TABLE client_identity ADD COLUMN "dex_admin" boolean;
-- +migrate Up
ALTER TABLE authd_user ADD COLUMN "created_at" bigint;
-- +migrate Up
ALTER TABLE session ADD COLUMN "nonce" text;
-- +migrate Up
CREATE TABLE refresh_token (
id bigint NOT NULL,
payload_hash text,
user_id text,
client_id text
);
CREATE SEQUENCE refresh_token_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE refresh_token_id_seq OWNED BY refresh_token.id;
ALTER TABLE ONLY refresh_token ALTER COLUMN id SET DEFAULT nextval('refresh_token_id_seq'::regclass);
ALTER TABLE ONLY refresh_token
ADD CONSTRAINT refresh_token_pkey PRIMARY KEY (id);
-- +migrate Up
ALTER TABLE ONLY authd_user
ADD CONSTRAINT authd_user_email_key UNIQUE (email);
This diff is collapsed.
...@@ -14,7 +14,10 @@ import ( ...@@ -14,7 +14,10 @@ import (
) )
const ( const (
userTableName = "dex_user" // This table is named authd_user for historical reasons; namely, that the
// original name of the project was authd, and there are existing tables out
// there that we don't want to have to rename in production.
userTableName = "authd_user"
remoteIdentityMappingTableName = "remote_identity_mapping" remoteIdentityMappingTableName = "remote_identity_mapping"
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment