diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 7571e5bf..42a31e05 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -84,8 +84,14 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele }, nil } + // if the network was set, pass it to the selector + sopts := opts.SelectOptions + if len(opts.Network) > 0 { + sopts = append(sopts, selector.WithDomain(opts.Network)) + } + // get next nodes from the selector - next, err := g.opts.Selector.Select(service, opts.SelectOptions...) + next, err := g.opts.Selector.Select(service, sopts...) if err != nil { if err == selector.ErrNotFound { return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error()) diff --git a/client/options.go b/client/options.go index 8ba14698..4baf3801 100644 --- a/client/options.go +++ b/client/options.go @@ -64,6 +64,8 @@ type CallOptions struct { ServiceToken bool // Duration to cache the response for CacheExpiry time.Duration + // Network to lookup the route within + Network string // Middleware for low level call func CallWrappers []CallWrapper @@ -338,6 +340,13 @@ func WithCache(c time.Duration) CallOption { } } +// WithNetwork is a CallOption which sets the network attribute +func WithNetwork(n string) CallOption { + return func(o *CallOptions) { + o.Network = n + } +} + func WithMessageContentType(ct string) MessageOption { return func(o *MessageOptions) { o.ContentType = ct diff --git a/client/selector/default.go b/client/selector/default.go index 255385d5..46be5ad5 100644 --- a/client/selector/default.go +++ b/client/selector/default.go @@ -38,14 +38,26 @@ func (c *registrySelector) Options() Options { } func (c *registrySelector) Select(service string, opts ...SelectOption) (Next, error) { - sopts := SelectOptions{ - Strategy: c.so.Strategy, - } - + sopts := SelectOptions{Strategy: c.so.Strategy} for _, opt := range opts { opt(&sopts) } + // a specific domain was requested, only lookup the services in that domain + if len(sopts.Domain) > 0 { + services, err := c.rc.GetService(service, registry.GetDomain(sopts.Domain)) + if err != nil && err != registry.ErrNotFound { + return nil, err + } + for _, filter := range sopts.Filters { + services = filter(services) + } + if len(services) == 0 { + return nil, ErrNoneAvailable + } + return sopts.Strategy(services), nil + } + // get the service. Because the service could be running in the current or the default domain, // we call both. For example, go.micro.service.foo could be running in the services current domain, // however the runtime (go.micro.runtime) will always be run in the default domain. diff --git a/client/selector/options.go b/client/selector/options.go index 806829d7..46409542 100644 --- a/client/selector/options.go +++ b/client/selector/options.go @@ -21,6 +21,7 @@ type Options struct { type SelectOptions struct { Filters []Filter Strategy Strategy + Domain string // Other options for implementations of the interface // can be stored in a context @@ -68,3 +69,10 @@ func WithStrategy(fn Strategy) SelectOption { o.Strategy = fn } } + +// WithDomain sets the registry domain to use for the selection +func WithDomain(d string) SelectOption { + return func(o *SelectOptions) { + o.Domain = d + } +} diff --git a/util/wrapper/wrapper.go b/util/wrapper/wrapper.go index 299a59fc..e5d7895a 100644 --- a/util/wrapper/wrapper.go +++ b/util/wrapper/wrapper.go @@ -222,10 +222,10 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper { ctx = metadata.Set(ctx, "Micro-Namespace", ns) } - // Check the issuer matches the services namespace. TODO: Stop allowing go.micro to access + // Check the issuer matches the services namespace. TODO: Stop allowing micro to access // any namespace and instead check for the server issuer. if account != nil && account.Issuer != ns && account.Issuer != "micro" { - return errors.Forbidden(req.Service(), "Account was not issued by %v", ns) + return errors.Forbidden(req.Service(), "Account was issued by %v, not %v", account.Issuer, ns) } // construct the resource