diff --git a/api/resolver/grpc/grpc.go b/api/resolver/grpc/grpc.go index 3cfe7871..127a88d2 100644 --- a/api/resolver/grpc/grpc.go +++ b/api/resolver/grpc/grpc.go @@ -13,7 +13,10 @@ type Resolver struct { 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 if req.URL.Path == "/" { return nil, errors.New("unknown name") @@ -28,7 +31,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } diff --git a/api/resolver/host/host.go b/api/resolver/host/host.go index f97e9415..6d028961 100644 --- a/api/resolver/host/host.go +++ b/api/resolver/host/host.go @@ -11,13 +11,16 @@ type Resolver struct { 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{ Name: req.Host, Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } diff --git a/api/resolver/options.go b/api/resolver/options.go index 1c48313e..51a67e6d 100644 --- a/api/resolver/options.go +++ b/api/resolver/options.go @@ -6,7 +6,6 @@ import ( type Options struct { Handler string - Domain 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 func WithServicePrefix(p string) Option { return func(o *Options) { @@ -39,6 +31,30 @@ func NewOptions(opts ...Option) Options { for _, o := range opts { 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 { options.Domain = registry.DefaultDomain } diff --git a/api/resolver/path/path.go b/api/resolver/path/path.go index dbce6e09..4cdd38ea 100644 --- a/api/resolver/path/path.go +++ b/api/resolver/path/path.go @@ -12,7 +12,10 @@ type Resolver struct { 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 == "/" { return nil, resolver.ErrNotFound } @@ -24,7 +27,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } diff --git a/api/resolver/resolver.go b/api/resolver/resolver.go index 110995d8..67da74f1 100644 --- a/api/resolver/resolver.go +++ b/api/resolver/resolver.go @@ -13,7 +13,7 @@ var ( // Resolver resolves requests to endpoints type Resolver interface { - Resolve(r *http.Request) (*Endpoint, error) + Resolve(r *http.Request, opts ...ResolveOption) (*Endpoint, error) String() string } diff --git a/api/resolver/subdomain/subdomain.go b/api/resolver/subdomain/subdomain.go index 199fcde4..f1c4bad7 100644 --- a/api/resolver/subdomain/subdomain.go +++ b/api/resolver/subdomain/subdomain.go @@ -22,21 +22,15 @@ type Resolver struct { resolver.Resolver } -func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { - // resolve the endpoint using the provided resolver - endpoint, err := r.Resolver.Resolve(req) - if err != nil { - return nil, err +func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) { + if dom := r.Domain(req); len(dom) > 0 { + opts = append(opts, resolver.Domain(dom)) } - // override the domain - endpoint.Domain = r.resolveDomain(req) - - // return the result - return endpoint, nil + return r.Resolver.Resolve(req, opts...) } -func (r *Resolver) resolveDomain(req *http.Request) string { +func (r *Resolver) Domain(req *http.Request) string { // determine the host, e.g. foobar.m3o.app host := req.URL.Hostname() if len(host) == 0 { @@ -49,24 +43,24 @@ func (r *Resolver) resolveDomain(req *http.Request) string { // check for an ip address if net.ParseIP(host) != nil { - return r.opts.Domain + return "" } // check for dev enviroment if host == "localhost" || host == "127.0.0.1" { - return r.opts.Domain + return "" } // extract the top level domain plus one (e.g. 'myapp.com') domain, err := publicsuffix.EffectiveTLDPlusOne(host) if err != nil { logger.Debugf("Unable to extract domain from %v", host) - return r.opts.Domain + return "" } // there was no subdomain 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" diff --git a/api/resolver/vpath/vpath.go b/api/resolver/vpath/vpath.go index 99486074..9a2b6cff 100644 --- a/api/resolver/vpath/vpath.go +++ b/api/resolver/vpath/vpath.go @@ -22,11 +22,13 @@ var ( 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 == "/" { return nil, errors.New("unknown name") } + options := resolver.NewResolveOptions(opts...) + parts := strings.Split(req.URL.Path[1:], "/") if len(parts) == 1 { return &resolver.Endpoint{ @@ -34,7 +36,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } @@ -45,7 +47,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } @@ -54,7 +56,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { Host: req.Host, Method: req.Method, Path: req.URL.Path, - Domain: r.opts.Domain, + Domain: options.Domain, }, nil } diff --git a/registry/etcd/etcd.go b/registry/etcd/etcd.go index 4e52b650..f768bd48 100644 --- a/registry/etcd/etcd.go +++ b/registry/etcd/etcd.go @@ -167,6 +167,13 @@ func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, op 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() // ensure the leases and registers are setup for this domain if _, ok := e.leases[options.Domain]; !ok { diff --git a/router/default.go b/router/default.go index 365d036e..2906fed2 100644 --- a/router/default.go +++ b/router/default.go @@ -674,6 +674,7 @@ func (r *router) Close() error { // remove event chan r.eventChan = nil + r.running = false return nil } diff --git a/router/table.go b/router/table.go index cd5e5815..5657d5f1 100644 --- a/router/table.go +++ b/router/table.go @@ -150,7 +150,7 @@ func (t *table) List() ([]Route, error) { func isMatch(route Route, address, gateway, network, router string, strategy Strategy) bool { // matches the values provided match := func(a, b string) bool { - if a == "*" || a == b { + if a == "*" || b == "*" || a == b { return true } return false diff --git a/web/service.go b/web/service.go index 643c9dbc..0a309eb6 100644 --- a/web/service.go +++ b/web/service.go @@ -141,10 +141,16 @@ func (s *service) register() 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 for i := 0; i < 3; i++ { // 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 regErr = err // backoff then retry