Merge pull request #1622 from micro/registry-multi-tenancy

Registry mutli-tenancy
This commit is contained in:
ben-toogood 2020-05-13 13:54:39 +01:00 committed by GitHub
commit fb255a7e5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 38 deletions

View File

@ -0,0 +1,21 @@
package service
import (
"context"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/registry"
)
type clientKey struct{}
// WithClient sets the RPC client
func WithClient(c client.Client) registry.Option {
return func(o *registry.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, clientKey{}, c)
}
}

View File

@ -46,6 +46,17 @@ func (s *serviceRegistry) Init(opts ...registry.Option) error {
for _, o := range opts {
o(&s.opts)
}
// extract the client from the context, fallback to grpc
var cli client.Client
if c, ok := s.opts.Context.Value(clientKey{}).(client.Client); ok {
cli = c
} else {
cli = grpc.NewClient()
}
s.client = pb.NewRegistryService(DefaultService, cli)
return nil
}
@ -171,21 +182,23 @@ func NewRegistry(opts ...registry.Option) registry.Registry {
// the registry address
addrs := options.Addrs
if len(addrs) == 0 {
addrs = []string{"127.0.0.1:8000"}
}
// use mdns as a fall back in case its used
mReg := registry.NewRegistry()
if options.Context == nil {
options.Context = context.TODO()
}
// create new client with mdns
cli := grpc.NewClient(
client.Registry(mReg),
)
// extract the client from the context, fallback to grpc
var cli client.Client
if c, ok := options.Context.Value(clientKey{}).(client.Client); ok {
cli = c
} else {
cli = grpc.NewClient()
}
// service name
// TODO: accept option
// service name. TODO: accept option
name := DefaultService
return &serviceRegistry{

View File

@ -1,6 +1,7 @@
package micro
import (
"fmt"
"os"
"os/signal"
rtime "runtime"
@ -15,6 +16,7 @@ import (
"github.com/micro/go-micro/v2/debug/trace"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/plugin"
registrySrv "github.com/micro/go-micro/v2/registry/service"
"github.com/micro/go-micro/v2/runtime"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/store"
@ -115,7 +117,8 @@ func (s *service) Init(opts ...Option) {
s.opts.Store.Init(store.Table(name))
// Set the client for the micro clients
// s.opts.Auth.Init(auth.WithClient(s.Client()))
s.opts.Auth.Init(auth.WithClient(s.Client()))
s.opts.Registry.Init(registrySrv.WithClient(s.Client()))
s.opts.Runtime.Init(runtime.WithClient(s.Client()))
s.opts.Store.Init(store.WithClient(s.Client()))
})
@ -205,6 +208,11 @@ func (s *service) Run() error {
logger.Infof("Starting [service] %s", s.Name())
}
// generate an auth account
if err := s.registerAuthAccount(); err != nil {
return err
}
if err := s.Start(); err != nil {
return err
}
@ -223,3 +231,27 @@ func (s *service) Run() error {
return s.Stop()
}
func (s *service) registerAuthAccount() error {
// generate a new auth account for the service
name := fmt.Sprintf("%v-%v", s.Name(), s.Server().Options().Id)
opts := []auth.GenerateOption{
auth.WithType("service"),
auth.WithRoles("service"),
auth.WithNamespace(s.Options().Auth.Options().Namespace),
}
acc, err := s.Options().Auth.Generate(name, opts...)
if err != nil {
return err
}
// generate a token
token, err := s.Options().Auth.Token(auth.WithCredentials(acc.ID, acc.Secret))
if err != nil {
return err
}
s.Options().Auth.Init(auth.ClientToken(token), auth.Credentials(acc.ID, acc.Secret))
logger.Infof("Auth [%v] Authenticated as %v", s.Options().Auth, name)
return nil
}

View File

@ -2,7 +2,6 @@ package wrapper
import (
"context"
"fmt"
"strings"
"time"
@ -182,7 +181,7 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac
return callWithToken(tok.AccessToken)
}
// if we have credentials we can generate a new token for the account
// generate a new token if we have credentials
if len(aaOpts.ID) > 0 && len(aaOpts.Secret) > 0 {
tok, err := aa.Token(auth.WithCredentials(aaOpts.ID, aaOpts.Secret))
if err != nil {
@ -198,31 +197,8 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac
return callWithToken(token)
}
// determine the type of service from the name. we do this so we can allocate
// different roles depending on the type of services. e.g. we don't want web
// services talking directly to the runtime. TODO: find a better way to determine
// the type of service
serviceType := "service"
if strings.Contains(a.name, "api") {
serviceType = "api"
} else if strings.Contains(a.name, "web") {
serviceType = "web"
}
// generate a new auth account for the service
name := fmt.Sprintf("%v-%v", a.name, a.id)
acc, err := aa.Generate(name, auth.WithNamespace(aaOpts.Namespace), auth.WithRoles(serviceType))
if err != nil {
return err
}
token, err := aa.Token(auth.WithCredentials(acc.ID, acc.Secret))
if err != nil {
return err
}
aa.Init(auth.ClientToken(token))
// use the token to execute the request
return callWithToken(token.AccessToken)
// call without an auth token
return a.Client.Call(ctx, req, rsp, opts...)
}
// AuthClient wraps requests with the auth header
@ -276,7 +252,9 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
}
// There is an account, set it in the context
ctx = auth.ContextWithAccount(ctx, account)
if len(account.ID) > 0 {
ctx = auth.ContextWithAccount(ctx, account)
}
// The user is authorised, allow the call
return h(ctx, req, rsp)