Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote/plugin support #353

Merged
merged 27 commits into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1171e9d
wip: engine2 passing test with updates service
umputun Jun 8, 2019
29ffa57
restore all service coverage with new engine
umputun Jun 8, 2019
fa15fb1
make new engine primary, rename package
umputun Jun 9, 2019
1013b5d
Merge branch 'master' into remote
umputun Jun 9, 2019
a6a7448
remote client adjusted to new engine flavour
umputun Jun 9, 2019
625dbff
split remote to common protocol package and engine implemetation
umputun Jun 9, 2019
fa83c00
initial ver of remote server
umputun Jun 9, 2019
3f73a01
implement DeleteUser soft mode to allow mapping for blocked users #341
umputun Jun 10, 2019
05a3871
remote server covered with tests
umputun Jun 10, 2019
465571a
fix remote client tests with id
umputun Jun 10, 2019
0722e64
switch list flag to struct param
umputun Jun 11, 2019
a098d17
Merge remote-tracking branch 'remotes/origin/master' into remote
umputun Jun 18, 2019
2ed7068
error responses of json api with json, time out on remote server close
umputun Jun 18, 2019
000e19a
Merge remote-tracking branch 'remotes/origin/master' into remote
umputun Jun 19, 2019
ab73d82
change remote interface to struct requests
umputun Jun 20, 2019
21cd81e
add remote implementation of admin store
umputun Jun 21, 2019
247e1e2
fix empty (no args) remote calls
umputun Jun 21, 2019
e83a4a2
support remote server group handler
umputun Jun 24, 2019
2b7ddcb
adjust remote tests, remove legacy mongo tests
umputun Jun 25, 2019
db59773
add remote selection to store and admin
umputun Jun 25, 2019
41e95f9
fix recreation of bdb in delete
umputun Jun 25, 2019
4810b01
larger limit for remote srv throttler
umputun Jun 25, 2019
8309dd8
clear mongo leftovers
umputun Jun 25, 2019
dc5e27a
clean drone build
umputun Jun 25, 2019
4727e37
lint: test warnings
umputun Jun 26, 2019
be86a72
lint: more test warns
umputun Jun 26, 2019
ea5fbca
add test for app with remote plugins
umputun Jun 26, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ debug.test
*.prof
*.test
remark42
/backend/var/
/backend/var/
compose-private-backend.yml
9 changes: 0 additions & 9 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ pipeline:
build:
image: golang:1.12-alpine
commands:
- sleep 5
- nslookup mongo
- nslookup mongo | grep Address | awk '{print $3}' > backend/.mongo
- cat backend/.mongo
- cd backend/app
- go build -v ./...

Expand Down Expand Up @@ -94,8 +90,3 @@ pipeline:
secrets: [ email_username, email_password ]
when:
status: [ changed, failure ]

services:
mongo:
image: mongo:3.6
command: [ --smallfiles ]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ debug.test
remark42
/bin/
/backend/var/
compose-private-backend.yml
6 changes: 0 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ install:
- docker-compose --version

script:
- docker run -d --name=mongo mongo:3.6 && sleep 3
- export MONGO_TEST=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongo)
- echo "running mongo on $MONGO_TEST"
- docker build
--build-arg COVERALLS_TOKEN=$COVERALLS_TOKEN
--build-arg CI=$CI
Expand All @@ -19,7 +16,4 @@ script:
--build-arg TRAVIS_PULL_REQUEST_SHA=$TRAVIS_PULL_REQUEST_SHA
--build-arg TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG
--build-arg TRAVIS_TAG=$TRAVIS_TAG
--build-arg MONGO_TEST=$MONGO_TEST
.
- docker rm -f mongo

7 changes: 1 addition & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ ARG DRONE_BRANCH
ARG DRONE_PULL_REQUEST

ARG SKIP_BACKEND_TEST
ARG MONGO_TEST

ADD backend /build/backend
ADD .git /build/.git
Expand All @@ -29,18 +28,14 @@ ENV GOFLAGS="-mod=vendor"

# run tests
RUN \
if [ -f .mongo ] ; then export MONGO_TEST=$(cat .mongo) ; fi && \
cd app && \
if [ -z "$SKIP_BACKEND_TEST" ] ; then \
go test -covermode=count -coverprofile=/profile.cov_tmp ./... && \
go test -p 1 -timeout=30s -covermode=count -coverprofile=/profile.cov_tmp ./... && \
cat /profile.cov_tmp | grep -v "_mock.go" > /profile.cov ; \
else echo "skip backend test" ; fi

RUN echo "mongo=${MONGO_TEST}" >> /etc/hosts

# linters
RUN if [ -z "$SKIP_BACKEND_TEST" ] ; then \
if [ -f .mongo ] ; then export MONGO_TEST=$(cat .mongo) ; fi && \
golangci-lint run --out-format=tab --disable-all --tests=false --enable=unconvert \
--enable=megacheck --enable=structcheck --enable=gas --enable=gocyclo --enable=dupl --enable=misspell \
--enable=unparam --enable=varcheck --enable=deadcode --enable=typecheck \
Expand Down
17 changes: 0 additions & 17 deletions backend/app/cmd/avatar.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package cmd

import (
"path"
"time"

bolt "github.com/coreos/bbolt"
log "github.com/go-pkgz/lgr"
"github.com/pkg/errors"

"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/mongo"
)

// AvatarCommand set of flags and command for avatar migration
Expand All @@ -18,7 +16,6 @@ import (
type AvatarCommand struct {
AvatarSrc AvatarGroup `group:"src" namespace:"src"`
AvatarDst AvatarGroup `group:"dst" namespace:"dst"`
Mongo MongoGroup `group:"mongo" namespace:"mongo" env-namespace:"MONGO"`

migrator AvatarMigrator
CommonOpts
Expand Down Expand Up @@ -78,13 +75,6 @@ func (ac *AvatarCommand) makeAvatarStore(gr AvatarGroup) (avatar.Store, error) {
return nil, err
}
return avatar.NewLocalFS(gr.FS.Path), nil
case "mongo":
mgServer, err := ac.makeMongo()
if err != nil {
return nil, errors.Wrap(err, "failed to create mongo server")
}
conn := mongo.NewConnection(mgServer, ac.Mongo.DB, "")
return avatar.NewGridFS(conn), nil
case "bolt":
if err := makeDirs(path.Dir(gr.Bolt.File)); err != nil {
return nil, err
Expand All @@ -93,10 +83,3 @@ func (ac *AvatarCommand) makeAvatarStore(gr AvatarGroup) (avatar.Store, error) {
}
return nil, errors.Errorf("unsupported avatar store type %s", gr.Type)
}

func (ac *AvatarCommand) makeMongo() (result *mongo.Server, err error) {
if ac.Mongo.URL == "" {
return nil, errors.New("no mongo URL provided")
}
return mongo.NewServerWithURL(ac.Mongo.URL, 10*time.Second)
}
29 changes: 6 additions & 23 deletions backend/app/cmd/avatar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,25 @@ import (

func TestAvatar_Execute(t *testing.T) {

mongoURL := os.Getenv("MONGO_TEST")
if mongoURL == "" {
mongoURL = "mongodb://localhost:27017/test"
}
if mongoURL == "skip" {
t.Skip("skip mongo app test")
}
defer os.RemoveAll("/tmp/ava-test")

// from fs to mongo
// from fs to bolt
cmd := AvatarCommand{migrator: &avatarMigratorMock{retCount: 100}}
cmd.SetCommon(CommonOpts{RemarkURL: "", SharedSecret: "123456"})
p := flags.NewParser(&cmd, flags.Default)
_, err := p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=mongo",
"--mongo.url=" + mongoURL, "--mongo.db=test_remark"})
require.Nil(t, err)
err = cmd.Execute(nil)
assert.NoError(t, err)

// from fs to bolt
cmd = AvatarCommand{migrator: &avatarMigratorMock{retCount: 100}}
cmd.SetCommon(CommonOpts{RemarkURL: "", SharedSecret: "123456"})
p = flags.NewParser(&cmd, flags.Default)
_, err = p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt",
_, err := p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt",
"--dst.bolt.file=/tmp/ava-test.db"})
require.Nil(t, err)
require.NoError(t, err)
err = cmd.Execute(nil)
assert.NoError(t, err)

// failed
cmd = AvatarCommand{migrator: &avatarMigratorMock{retCount: 0, retError: errors.New("failed blah")}}
cmd.SetCommon(CommonOpts{RemarkURL: "", SharedSecret: "123456"})
p = flags.NewParser(&cmd, flags.Default)
_, err = p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=mongo",
"--mongo.url=" + mongoURL, "--mongo.db=test_remark"})
require.Nil(t, err)
_, err = p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt",
"--dst.bolt.file=/tmp/ava-test2.db"})
require.NoError(t, err)
err = cmd.Execute(nil)
assert.Error(t, err, "failed blah")
}
Expand Down
83 changes: 33 additions & 50 deletions backend/app/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/auth/provider"
"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/mongo"
"github.com/go-pkgz/rest/cache"

"github.com/umputun/remark/backend/app/migrator"
Expand All @@ -33,6 +32,7 @@ import (
"github.com/umputun/remark/backend/app/store/admin"
"github.com/umputun/remark/backend/app/store/engine"
"github.com/umputun/remark/backend/app/store/image"
"github.com/umputun/remark/backend/app/store/remote"
"github.com/umputun/remark/backend/app/store/service"
)

Expand All @@ -41,7 +41,6 @@ type ServerCommand struct {
Store StoreGroup `group:"store" namespace:"store" env-namespace:"STORE"`
Avatar AvatarGroup `group:"avatar" namespace:"avatar" env-namespace:"AVATAR"`
Cache CacheGroup `group:"cache" namespace:"cache" env-namespace:"CACHE"`
Mongo MongoGroup `group:"mongo" namespace:"mongo" env-namespace:"MONGO"`
Admin AdminGroup `group:"admin" namespace:"admin" env-namespace:"ADMIN"`
Notify NotifyGroup `group:"notify" namespace:"notify" env-namespace:"NOTIFY"`
Image ImageGroup `group:"image" namespace:"image" env-namespace:"IMAGE"`
Expand Down Expand Up @@ -89,16 +88,17 @@ type AuthGroup struct {

// StoreGroup defines options group for store params
type StoreGroup struct {
Type string `long:"type" env:"TYPE" description:"type of storage" choice:"bolt" choice:"mongo" default:"bolt"`
Type string `long:"type" env:"TYPE" description:"type of storage" choice:"bolt" choice:"remote" default:"bolt"`
Bolt struct {
Path string `long:"path" env:"PATH" default:"./var" description:"parent dir for bolt files"`
Timeout time.Duration `long:"timeout" env:"TIMEOUT" default:"30s" description:"bolt timeout"`
} `group:"bolt" namespace:"bolt" env-namespace:"BOLT"`
Remote RemoteGroup `group:"remote" namespace:"remote" env-namespace:"REMOTE"`
}

// ImageGroup defines options group for store pictures
type ImageGroup struct {
Type string `long:"type" env:"TYPE" description:"type of storage" choice:"fs" choice:"bolt" choice:"mongo" default:"fs"`
Type string `long:"type" env:"TYPE" description:"type of storage" choice:"fs" choice:"bolt" default:"fs"`
FS struct {
Path string `long:"path" env:"PATH" default:"./var/pictures" description:"images location"`
Staging string `long:"staging" env:"STAGING" default:"./var/pictures.staging" description:"staging location"`
Expand All @@ -114,7 +114,7 @@ type ImageGroup struct {

// AvatarGroup defines options group for avatar params
type AvatarGroup struct {
Type string `long:"type" env:"TYPE" description:"type of avatar storage" choice:"fs" choice:"bolt" choice:"mongo" default:"fs"`
Type string `long:"type" env:"TYPE" description:"type of avatar storage" choice:"fs" choice:"bolt" default:"fs"`
FS struct {
Path string `long:"path" env:"PATH" default:"./var/avatars" description:"avatars location"`
} `group:"fs" namespace:"fs" env-namespace:"FS"`
Expand All @@ -126,27 +126,22 @@ type AvatarGroup struct {

// CacheGroup defines options group for cache params
type CacheGroup struct {
Type string `long:"type" env:"TYPE" description:"type of cache" choice:"mem" choice:"mongo" choice:"none" default:"mem"`
Type string `long:"type" env:"TYPE" description:"type of cache" choice:"mem" choice:"none" default:"mem"`
Max struct {
Items int `long:"items" env:"ITEMS" default:"1000" description:"max cached items"`
Value int `long:"value" env:"VALUE" default:"65536" description:"max size of cached value"`
Size int64 `long:"size" env:"SIZE" default:"50000000" description:"max size of total cache"`
} `group:"max" namespace:"max" env-namespace:"MAX"`
}

// MongoGroup holds all mongo params, used by store, avatar and cache
type MongoGroup struct {
URL string `long:"url" env:"URL" description:"mongo url"`
DB string `long:"db" env:"DB" default:"remark42" description:"mongo database"`
}

// AdminGroup defines options group for admin params
type AdminGroup struct {
Type string `long:"type" env:"TYPE" description:"type of admin store" choice:"shared" choice:"mongo" default:"shared"`
Type string `long:"type" env:"TYPE" description:"type of admin store" choice:"shared" choice:"remote" default:"shared"`
Shared struct {
Admins []string `long:"id" env:"ID" description:"admin(s) ids" env-delim:","`
Email string `long:"email" env:"EMAIL" default:"" description:"admin email"`
} `group:"shared" namespace:"shared" env-namespace:"SHARED"`
Remote RemoteGroup `group:"remote" namespace:"remote" env-namespace:"REMOTE"`
}

// NotifyGroup defines options for notification
Expand Down Expand Up @@ -178,6 +173,14 @@ type StreamGroup struct {
MaxActive int `long:"max" env:"MAX" default:"500" description:"max number of parallel streams"`
}

// RemoteGroup defines options for remote modules (plugins)
type RemoteGroup struct {
API string `long:"api" env:"API" description:"remote extension api url"`
TimeOut time.Duration `long:"timeout" env:"TIMEOUT" default:"5s" description:"http timeout"`
AuthUser string `long:"auth_user" env:"AUTH_USER" description:"basic auth user name"`
AuthPassword string `long:"auth_passwd" env:"AUTH_PASSWD" description:"basic auth user password"`
}

// serverApp holds all active objects
type serverApp struct {
*ServerCommand
Expand Down Expand Up @@ -249,7 +252,7 @@ func (s *ServerCommand) newServerApp() (*serverApp, error) {
log.Printf("[DEBUG] image service for url=%s, ttl=%v", imageService.ImageAPI, imageService.TTL)

dataService := &service.DataStore{
Interface: storeEngine,
Engine: storeEngine,
EditDuration: s.EditDuration,
AdminStore: adminStore,
MaxCommentSize: s.MaxCommentSize,
Expand Down Expand Up @@ -414,13 +417,14 @@ func (s *ServerCommand) makeDataStore() (result engine.Interface, err error) {
sites = append(sites, engine.BoltSite{SiteID: site, FileName: fmt.Sprintf("%s/%s.db", s.Store.Bolt.Path, site)})
}
result, err = engine.NewBoltDB(bolt.Options{Timeout: s.Store.Bolt.Timeout}, sites...)
case "mongo":
mgServer, e := s.makeMongo()
if e != nil {
return result, errors.Wrap(e, "failed to create mongo server")
}
conn := mongo.NewConnection(mgServer, s.Mongo.DB, "")
result, err = engine.NewMongo(conn, 500, 100*time.Millisecond)
case "remote":
r := &engine.Remote{Client: remote.Client{
API: s.Store.Remote.API,
Client: http.Client{Timeout: s.Store.Remote.TimeOut},
AuthUser: s.Store.Remote.AuthUser,
AuthPasswd: s.Store.Remote.AuthPassword,
}}
return r, nil
default:
return nil, errors.Errorf("unsupported store type %s", s.Store.Type)
}
Expand All @@ -436,13 +440,6 @@ func (s *ServerCommand) makeAvatarStore() (avatar.Store, error) {
return nil, err
}
return avatar.NewLocalFS(s.Avatar.FS.Path), nil
case "mongo":
mgServer, err := s.makeMongo()
if err != nil {
return nil, errors.Wrap(err, "failed to create mongo server")
}
conn := mongo.NewConnection(mgServer, s.Mongo.DB, "")
return avatar.NewGridFS(conn), nil
case "bolt":
if err := makeDirs(path.Dir(s.Avatar.Bolt.File)); err != nil {
return nil, err
Expand Down Expand Up @@ -485,13 +482,14 @@ func (s *ServerCommand) makeAdminStore() (admin.Store, error) {
}
}
return admin.NewStaticStore(s.SharedSecret, s.Admin.Shared.Admins, s.Admin.Shared.Email), nil
case "mongo":
mgServer, e := s.makeMongo()
if e != nil {
return nil, errors.Wrap(e, "failed to create mongo server")
}
conn := mongo.NewConnection(mgServer, s.Mongo.DB, "admin")
return admin.NewMongoStore(conn, s.SharedSecret), nil
case "remote":
r := &admin.Remote{Client: remote.Client{
API: s.Admin.Remote.API,
Client: http.Client{Timeout: s.Admin.Remote.TimeOut},
AuthUser: s.Admin.Remote.AuthUser,
AuthPasswd: s.Admin.Remote.AuthPassword,
}}
return r, nil
default:
return nil, errors.Errorf("unsupported admin store type %s", s.Admin.Type)
}
Expand All @@ -503,27 +501,12 @@ func (s *ServerCommand) makeCache() (cache.LoadingCache, error) {
case "mem":
return cache.NewMemoryCache(cache.MaxCacheSize(s.Cache.Max.Size), cache.MaxValSize(s.Cache.Max.Value),
cache.MaxKeys(s.Cache.Max.Items))
// case "mongo":
// mgServer, err := s.makeMongo()
// if err != nil {
// return nil, errors.Wrap(err, "failed to create mongo server")
// }
// conn := mongo.NewConnection(mgServer, s.Mongo.DB, "cache")
// return cache.NewMongoCache(conn, cache.MaxCacheSize(s.Cache.Max.Size), cache.MaxValSize(s.Cache.Max.Value),
// cache.MaxKeys(s.Cache.Max.Items))
case "none":
return &cache.Nop{}, nil
}
return nil, errors.Errorf("unsupported cache type %s", s.Cache.Type)
}

func (s *ServerCommand) makeMongo() (result *mongo.Server, err error) {
if s.Mongo.URL == "" {
return nil, errors.New("no mongo URL provided")
}
return mongo.NewServerWithURL(s.Mongo.URL, 10*time.Second)
}

func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) {

providers := 0
Expand Down
Loading