Skip to content

Commit

Permalink
all: add ability to load database connectors from plugins
Browse files Browse the repository at this point in the history
arekkas authored Jun 15, 2017
1 parent d18c68a commit f64771f
Showing 17 changed files with 221 additions and 37 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -13,4 +13,6 @@ output/
_book/
dist/
coverage.*
docs/api.swagger.json
docs/api.swagger.json
Dockerfile-plugin-*
plugin-*.so
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM golang:1.8-alpine

RUN apk add --no-cache git
RUN apk add --no-cache git build-base
RUN go get github.com/Masterminds/glide
WORKDIR /go/src/github.com/ory/hydra

3 changes: 2 additions & 1 deletion Dockerfile-automigrate
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM golang:1.8-alpine

RUN apk add --no-cache git && go get github.com/Masterminds/glide
RUN apk add --no-cache git build-base
RUN go get github.com/Masterminds/glide
WORKDIR /go/src/github.com/ory/hydra

ADD ./glide.yaml ./glide.yaml
3 changes: 2 additions & 1 deletion Dockerfile-demo
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM golang:1.8-alpine

RUN apk add --no-cache git && go get github.com/Masterminds/glide
RUN apk add --no-cache git build-base
RUN go get github.com/Masterminds/glide
WORKDIR /go/src/github.com/ory/hydra

ADD ./glide.yaml ./glide.yaml
3 changes: 2 additions & 1 deletion Dockerfile-http
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM golang:1.8-alpine

RUN apk add --no-cache git && go get github.com/Masterminds/glide
RUN apk add --no-cache git build-base
RUN go get github.com/Masterminds/glide
WORKDIR /go/src/github.com/ory/hydra

ADD ./glide.yaml ./glide.yaml
2 changes: 1 addition & 1 deletion Dockerfile-without-telemetry
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM golang:1.8-alpine

RUN apk add --no-cache git
RUN apk add --no-cache git build-base
RUN go get github.com/Masterminds/glide
WORKDIR /go/src/github.com/ory/hydra

1 change: 0 additions & 1 deletion client/manager_test.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import (
"testing"

"github.com/julienschmidt/httprouter"
_ "github.com/lib/pq"
"github.com/ory/fosite"
"github.com/ory/herodot"
. "github.com/ory/hydra/client"
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -91,6 +91,9 @@ func initConfig() {
viper.BindEnv("CONSENT_URL")
viper.SetDefault("CONSENT_URL", "")

viper.BindEnv("DATABASE_PLUGIN")
viper.SetDefault("DATABASE_PLUGIN", "")

viper.BindEnv("DATABASE_URL")
viper.SetDefault("DATABASE_URL", "")

8 changes: 8 additions & 0 deletions cmd/server/handler_client_factory.go
Original file line number Diff line number Diff line change
@@ -21,9 +21,17 @@ func newClientManager(c *config.Config) client.Manager {
DB: con.GetDatabase(),
Hasher: ctx.Hasher,
}
case *config.PluginConnection:
if m, err := con.NewClientManager(); err != nil {
c.GetLogger().Fatalf("Could not load client manager plugin %s", err)
} else {
return m
}
break
default:
panic("Unknown connection type.")
}
return nil
}

func newClientHandler(c *config.Config, router *httprouter.Router, manager client.Manager) *client.Handler {
7 changes: 7 additions & 0 deletions cmd/server/handler_jwk_factory.go
Original file line number Diff line number Diff line change
@@ -22,6 +22,13 @@ func injectJWKManager(c *config.Config) {
},
}
break
case *config.PluginConnection:
var err error
ctx.KeyManager, err = con.NewJWKManager()
if err != nil {
c.GetLogger().Fatalf("Could not load client manager plugin %s", err)
}
break
default:
c.GetLogger().Fatalf("Unknown connection type.")
}
6 changes: 6 additions & 0 deletions cmd/server/handler_oauth2_factory.go
Original file line number Diff line number Diff line change
@@ -40,6 +40,12 @@ func injectFositeStore(c *config.Config, clients client.Manager) {
L: c.GetLogger(),
}
break
case *config.PluginConnection:
var err error
if store, err = con.NewOAuth2Manager(clients); err != nil {
c.GetLogger().Fatalf("Could not load client manager plugin %s", err)
}
break
default:
panic("Unknown connection type.")
}
3 changes: 3 additions & 0 deletions config/backend_memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package config

type MemoryConnection struct{}
139 changes: 139 additions & 0 deletions config/backend_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package config

import (
"plugin"
"github.com/ory/ladon"
"github.com/ory/hydra/client"
"github.com/ory/hydra/warden/group"
"github.com/ory/hydra/jwk"
"github.com/ory/hydra/pkg"
"github.com/pkg/errors"
"github.com/Sirupsen/logrus"
"github.com/ory/fosite"
"github.com/jmoiron/sqlx"
)

type PluginConnection struct {
Config *Config
plugin *plugin.Plugin
didConnect bool
Logger logrus.FieldLogger
db *sqlx.DB
}

func (c *PluginConnection) load() error {
if c.plugin != nil {
return nil
}

cf := c.Config
p, err := plugin.Open(cf.DatabasePlugin)
if err != nil {
return errors.WithStack(err)
}

c.plugin = p
return nil
}

func (c *PluginConnection) Connect() error {
cf := c.Config
if c.didConnect {
return nil
}

if err := c.load(); err != nil {
return errors.WithStack(err)
}

if l, err := c.plugin.Lookup("Connect"); err != nil {
return errors.Wrap(err, "Unable to look up `Connect`")
} else if con, ok := l.(func(url string) (*sqlx.DB, error)); !ok {
return errors.New("Unable to type assert `Connect`")
} else {
if db, err := con(cf.DatabaseURL); err != nil {
return errors.Wrap(err, "Could not connect to database")
} else {
cf.GetLogger().Info("Successfully connected through database plugin")
c.db = db
cf.GetLogger().Debugf("Address of database plugin is: %s", c.db)
if err := db.Ping(); err != nil {
cf.GetLogger().WithError(err).Fatal("Could not ping database connection from plugin")
}
}
}
return nil
}

func (c *PluginConnection) NewClientManager() (client.Manager, error) {
if err := c.load(); err != nil {
return nil, errors.WithStack(err)
}

ctx := c.Config.Context()
if l, err := c.plugin.Lookup("NewClientManager"); err != nil {
return nil, errors.Wrap(err, "Unable to look up `NewClientManager`")
} else if m, ok := l.(func(*sqlx.DB, fosite.Hasher) client.Manager); !ok {
return nil, errors.New("Unable to type assert `NewClientManager`")
} else {
return m(c.db, ctx.Hasher), nil
}
}

func (c *PluginConnection) NewGroupManager() (group.Manager, error) {
if err := c.load(); err != nil {
return nil, errors.WithStack(err)
}

if l, err := c.plugin.Lookup("NewGroupManager"); err != nil {
return nil, errors.Wrap(err, "Unable to look up `NewGroupManager`")
} else if m, ok := l.(func(*sqlx.DB) group.Manager); !ok {
return nil, errors.New("Unable to type assert `NewGroupManager`")
} else {
return m(c.db), nil
}
}

func (c *PluginConnection) NewJWKManager() (jwk.Manager, error) {
if err := c.load(); err != nil {
return nil, errors.WithStack(err)
}

if l, err := c.plugin.Lookup("NewJWKManager"); err != nil {
return nil, errors.Wrap(err, "Unable to look up `NewJWKManager`")
} else if m, ok := l.(func(*sqlx.DB, *jwk.AEAD) jwk.Manager); !ok {
return nil, errors.New("Unable to type assert `NewJWKManager`")
} else {
return m(c.db, &jwk.AEAD{
Key: c.Config.GetSystemSecret(),
}), nil
}
}

func (c *PluginConnection) NewOAuth2Manager(clientManager client.Manager) (pkg.FositeStorer, error) {
if err := c.load(); err != nil {
return nil, errors.WithStack(err)
}

if l, err := c.plugin.Lookup("NewOAuth2Manager"); err != nil {
return nil, errors.Wrap(err, "Unable to look up `NewOAuth2Manager`")
} else if m, ok := l.(func(*sqlx.DB, client.Manager, logrus.FieldLogger) pkg.FositeStorer); !ok {
return nil, errors.New("Unable to type assert `NewOAuth2Manager`")
} else {
return m(c.db, clientManager, c.Config.GetLogger()), nil
}
}

func (c *PluginConnection) NewPolicyManager() (ladon.Manager, error) {
if err := c.load(); err != nil {
return nil, errors.WithStack(err)
}

if l, err := c.plugin.Lookup("NewPolicyManager"); err != nil {
return nil, errors.Wrap(err, "Unable to look up `NewPolicyManager`")
} else if m, ok := l.(func(*sqlx.DB) ladon.Manager); !ok {
return nil, errors.Errorf("Unable to type assert `NewPolicyManager`, got %v", l)
} else {
return m(c.db), nil
}
}
8 changes: 3 additions & 5 deletions config/backend_connections.go → config/backend_sql.go
Original file line number Diff line number Diff line change
@@ -15,8 +15,6 @@ import (
"github.com/pkg/errors"
)

type MemoryConnection struct{}

type SQLConnection struct {
db *sqlx.DB
URL *url.URL
@@ -52,15 +50,15 @@ func (c *SQLConnection) GetDatabase() *sqlx.DB {
}

if c.db, err = sqlx.Open(clean.Scheme, u); err != nil {
return errors.Errorf("Could not connect to SQL: %s", err)
return errors.Errorf("Could not Connect to SQL: %s", err)
} else if err := c.db.Ping(); err != nil {
return errors.Errorf("Could not connect to SQL: %s", err)
return errors.Errorf("Could not Connect to SQL: %s", err)
}

c.L.Infof("Connected to SQL!")
return nil
}); err != nil {
c.L.Fatalf("Could not connect to SQL: %s", err)
c.L.Fatalf("Could not Connect to SQL: %s", err)
}

maxConns := maxParallelism() * 2
Original file line number Diff line number Diff line change
@@ -10,10 +10,10 @@ import (
"time"

"github.com/Sirupsen/logrus"
"github.com/bmizerany/assert"
"github.com/jmoiron/sqlx"
"github.com/ory/dockertest"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)

var (
@@ -102,7 +102,7 @@ func TestSQLConnection(t *testing.T) {
func killAll() {
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not connect to pool because %s", err)
log.Fatalf("Could not Connect to pool because %s", err)
}

for _, resource := range resources {
@@ -122,7 +122,7 @@ func bootstrapMySQL() *url.URL {
pool, err := dockertest.NewPool("")
pool.MaxWait = time.Minute * 5
if err != nil {
log.Fatalf("Could not connect to docker: %s", err)
log.Fatalf("Could not Connect to docker: %s", err)
}

resource, err := pool.Run("mysql", "5.7", []string{"MYSQL_ROOT_PASSWORD=secret"})
@@ -141,7 +141,7 @@ func bootstrapMySQL() *url.URL {
return db.Ping()
}); err != nil {
pool.Purge(resource)
log.Fatalf("Could not connect to docker: %s", err)
log.Fatalf("Could not Connect to docker: %s", err)
}

resources = append(resources, resource)
@@ -156,7 +156,7 @@ func bootstrapPostgres() *url.URL {

pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not connect to docker: %s", err)
log.Fatalf("Could not Connect to docker: %s", err)
}

resource, err := pool.Run("postgres", "9.6", []string{"POSTGRES_PASSWORD=secret", "POSTGRES_DB=hydra"})
@@ -175,7 +175,7 @@ func bootstrapPostgres() *url.URL {
return db.Ping()
}); err != nil {
pool.Purge(resource)
log.Fatalf("Could not connect to docker: %s", err)
log.Fatalf("Could not Connect to docker: %s", err)
}

resources = append(resources, resource)
Loading
Oops, something went wrong.

0 comments on commit f64771f

Please sign in to comment.