api/resolver: add resolve options (#1756)
* api/resolver: Resolve options * router/registry: fix init bug * router/registry: fix wildcard query bug * web: fix registation domain bug * registry/etcd: pass domain in service metadata * api/resolver/subdomain: expose domain func * Update api/resolver/subdomain/subdomain.go Co-authored-by: Dominic Wong <domwongemail@googlemail.com> Co-authored-by: Dominic Wong <domwongemail@googlemail.com>
This commit is contained in:
parent
132c1e35fe
commit
df3e5364ca
@ -13,7 +13,10 @@ type Resolver struct {
|
|||||||
opts resolver.Options
|
opts resolver.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {
|
||||||
|
// parse options
|
||||||
|
options := resolver.NewResolveOptions(opts...)
|
||||||
|
|
||||||
// /foo.Bar/Service
|
// /foo.Bar/Service
|
||||||
if req.URL.Path == "/" {
|
if req.URL.Path == "/" {
|
||||||
return nil, errors.New("unknown name")
|
return nil, errors.New("unknown name")
|
||||||
@ -28,7 +31,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
|||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,13 +11,16 @@ type Resolver struct {
|
|||||||
opts resolver.Options
|
opts resolver.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {
|
||||||
|
// parse options
|
||||||
|
options := resolver.NewResolveOptions(opts...)
|
||||||
|
|
||||||
return &resolver.Endpoint{
|
return &resolver.Endpoint{
|
||||||
Name: req.Host,
|
Name: req.Host,
|
||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Handler string
|
Handler string
|
||||||
Domain string
|
|
||||||
ServicePrefix string
|
ServicePrefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,13 +18,6 @@ func WithHandler(h string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDomain sets the namespace option
|
|
||||||
func WithDomain(n string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Domain = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithServicePrefix sets the ServicePrefix option
|
// WithServicePrefix sets the ServicePrefix option
|
||||||
func WithServicePrefix(p string) Option {
|
func WithServicePrefix(p string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@ -39,6 +31,30 @@ func NewOptions(opts ...Option) Options {
|
|||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveOptions are used when resolving a request
|
||||||
|
type ResolveOptions struct {
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveOption sets an option
|
||||||
|
type ResolveOption func(*ResolveOptions)
|
||||||
|
|
||||||
|
// Domain sets the resolve Domain option
|
||||||
|
func Domain(n string) ResolveOption {
|
||||||
|
return func(o *ResolveOptions) {
|
||||||
|
o.Domain = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewResolveOptions returns new initialised resolve options
|
||||||
|
func NewResolveOptions(opts ...ResolveOption) ResolveOptions {
|
||||||
|
var options ResolveOptions
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
if len(options.Domain) == 0 {
|
if len(options.Domain) == 0 {
|
||||||
options.Domain = registry.DefaultDomain
|
options.Domain = registry.DefaultDomain
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,10 @@ type Resolver struct {
|
|||||||
opts resolver.Options
|
opts resolver.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {
|
||||||
|
// parse options
|
||||||
|
options := resolver.NewResolveOptions(opts...)
|
||||||
|
|
||||||
if req.URL.Path == "/" {
|
if req.URL.Path == "/" {
|
||||||
return nil, resolver.ErrNotFound
|
return nil, resolver.ErrNotFound
|
||||||
}
|
}
|
||||||
@ -24,7 +27,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
|||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ var (
|
|||||||
|
|
||||||
// Resolver resolves requests to endpoints
|
// Resolver resolves requests to endpoints
|
||||||
type Resolver interface {
|
type Resolver interface {
|
||||||
Resolve(r *http.Request) (*Endpoint, error)
|
Resolve(r *http.Request, opts ...ResolveOption) (*Endpoint, error)
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,21 +22,15 @@ type Resolver struct {
|
|||||||
resolver.Resolver
|
resolver.Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {
|
||||||
// resolve the endpoint using the provided resolver
|
if dom := r.Domain(req); len(dom) > 0 {
|
||||||
endpoint, err := r.Resolver.Resolve(req)
|
opts = append(opts, resolver.Domain(dom))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// override the domain
|
return r.Resolver.Resolve(req, opts...)
|
||||||
endpoint.Domain = r.resolveDomain(req)
|
|
||||||
|
|
||||||
// return the result
|
|
||||||
return endpoint, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) resolveDomain(req *http.Request) string {
|
func (r *Resolver) Domain(req *http.Request) string {
|
||||||
// determine the host, e.g. foobar.m3o.app
|
// determine the host, e.g. foobar.m3o.app
|
||||||
host := req.URL.Hostname()
|
host := req.URL.Hostname()
|
||||||
if len(host) == 0 {
|
if len(host) == 0 {
|
||||||
@ -49,24 +43,24 @@ func (r *Resolver) resolveDomain(req *http.Request) string {
|
|||||||
|
|
||||||
// check for an ip address
|
// check for an ip address
|
||||||
if net.ParseIP(host) != nil {
|
if net.ParseIP(host) != nil {
|
||||||
return r.opts.Domain
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for dev enviroment
|
// check for dev enviroment
|
||||||
if host == "localhost" || host == "127.0.0.1" {
|
if host == "localhost" || host == "127.0.0.1" {
|
||||||
return r.opts.Domain
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the top level domain plus one (e.g. 'myapp.com')
|
// extract the top level domain plus one (e.g. 'myapp.com')
|
||||||
domain, err := publicsuffix.EffectiveTLDPlusOne(host)
|
domain, err := publicsuffix.EffectiveTLDPlusOne(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debugf("Unable to extract domain from %v", host)
|
logger.Debugf("Unable to extract domain from %v", host)
|
||||||
return r.opts.Domain
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// there was no subdomain
|
// there was no subdomain
|
||||||
if host == domain {
|
if host == domain {
|
||||||
return r.opts.Domain
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the domain from the host, leaving the subdomain, e.g. "staging.foo.myapp.com" => "staging.foo"
|
// remove the domain from the host, leaving the subdomain, e.g. "staging.foo.myapp.com" => "staging.foo"
|
||||||
|
@ -22,11 +22,13 @@ var (
|
|||||||
re = regexp.MustCompile("^v[0-9]+$")
|
re = regexp.MustCompile("^v[0-9]+$")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {
|
||||||
if req.URL.Path == "/" {
|
if req.URL.Path == "/" {
|
||||||
return nil, errors.New("unknown name")
|
return nil, errors.New("unknown name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options := resolver.NewResolveOptions(opts...)
|
||||||
|
|
||||||
parts := strings.Split(req.URL.Path[1:], "/")
|
parts := strings.Split(req.URL.Path[1:], "/")
|
||||||
if len(parts) == 1 {
|
if len(parts) == 1 {
|
||||||
return &resolver.Endpoint{
|
return &resolver.Endpoint{
|
||||||
@ -34,7 +36,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
|||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
|||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
|||||||
Host: req.Host,
|
Host: req.Host,
|
||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Domain: r.opts.Domain,
|
Domain: options.Domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +167,13 @@ func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, op
|
|||||||
options.Domain = defaultDomain
|
options.Domain = defaultDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the domain in metadata so it can be retrieved by wildcard queries
|
||||||
|
if s.Metadata == nil {
|
||||||
|
s.Metadata = map[string]string{"domain": options.Domain}
|
||||||
|
} else {
|
||||||
|
s.Metadata["domain"] = options.Domain
|
||||||
|
}
|
||||||
|
|
||||||
e.Lock()
|
e.Lock()
|
||||||
// ensure the leases and registers are setup for this domain
|
// ensure the leases and registers are setup for this domain
|
||||||
if _, ok := e.leases[options.Domain]; !ok {
|
if _, ok := e.leases[options.Domain]; !ok {
|
||||||
|
@ -674,6 +674,7 @@ func (r *router) Close() error {
|
|||||||
|
|
||||||
// remove event chan
|
// remove event chan
|
||||||
r.eventChan = nil
|
r.eventChan = nil
|
||||||
|
r.running = false
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ func (t *table) List() ([]Route, error) {
|
|||||||
func isMatch(route Route, address, gateway, network, router string, strategy Strategy) bool {
|
func isMatch(route Route, address, gateway, network, router string, strategy Strategy) bool {
|
||||||
// matches the values provided
|
// matches the values provided
|
||||||
match := func(a, b string) bool {
|
match := func(a, b string) bool {
|
||||||
if a == "*" || a == b {
|
if a == "*" || b == "*" || a == b {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -141,10 +141,16 @@ func (s *service) register() error {
|
|||||||
|
|
||||||
var regErr error
|
var regErr error
|
||||||
|
|
||||||
|
// register options
|
||||||
|
rOpts := []registry.RegisterOption{
|
||||||
|
registry.RegisterTTL(s.opts.RegisterTTL),
|
||||||
|
registry.RegisterDomain(s.opts.Service.Server().Options().Namespace),
|
||||||
|
}
|
||||||
|
|
||||||
// try three times if necessary
|
// try three times if necessary
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
// attempt to register
|
// attempt to register
|
||||||
if err := r.Register(s.srv, registry.RegisterTTL(s.opts.RegisterTTL)); err != nil {
|
if err := r.Register(s.srv, rOpts...); err != nil {
|
||||||
// set the error
|
// set the error
|
||||||
regErr = err
|
regErr = err
|
||||||
// backoff then retry
|
// backoff then retry
|
||||||
|
Loading…
Reference in New Issue
Block a user