http-add-on icon indicating copy to clipboard operation
http-add-on copied to clipboard

Wildcard support for multi-tenant interceptor

Open comron opened this issue 3 years ago • 5 comments

Allow for wildcards when specifying Host headers and routing information for interceptor and scaler.

Use-Case

Some services might have multiple hostnames, say for multiple customers in the form of "customername.service.example.com". So supplying a single Host header for routing/scaling wont suffice. We would need to support simple wildcards (*.service.exmaple.com") at the very least for this case. It might also be desirable to have the host parameter be a list rather than a single value.

Specification

I'm not intimately familiar with the internals of the project but my first take would be:

  1. When defining the host in an HTTPScaledObject allow for wildcards (and possibly multiple values)
  2. The queue used for keeping track of pending requests should match an incoming Host header with all the hosts and wildcards it knows about.
  3. Update the routing table to handle routing for wildcard HTTPScaledObject

comron avatar Oct 01 '21 19:10 comron

@comron sounds like a great idea! We'll get this implemented and released in v0.3.0.

arschles avatar Oct 01 '21 21:10 arschles

Hi there! So i did an initial implementation of this issue with the core logic in Table, something like:

func (t *Table) AddTarget(
	host string,
	target Target) error {
	n := strings.Count(host, "*")
	if n > 0 && (!strings.HasPrefix(host, "*") || n > 1) {
		return fmt.Errorf("invalid wildcard for host %s", host)
	} else if n > 0 {
		host = "^" + strings.Replace(host, "*", "[a-zA-Z0-9-]+", 1) + "$"
	}

	t.l.Lock()
	defer t.l.Unlock()
	_, err := t.lookup(host)
	if err == ErrTargetNotFound {
		t.m[host] = target
		return nil
	}
	return fmt.Errorf(
		"host %s is already registered in the routing table",
		host,
	)
}

func (t *Table) lookup(host string) (string, error) {
	_, ok := t.m[host]
	if ok {
		return host, nil
	}
	for k := range t.m {
		if matched, _ := regexp.MatchString(k, host); matched {
			return k, nil
		}
	}
	return "", ErrTargetNotFound
}

What do you all think about this? Should i simplify the solution? Thanks!!!

andresrsanchez avatar Dec 22 '21 11:12 andresrsanchez

On an initial look, this code looks good, but I'm on holiday looking at it from my iPad, so I'll take a more in-depth look when I'm back. Thank for putting it together!

arschles avatar Dec 23 '21 18:12 arschles

@andresrsanchez I looked in more depth at the code you posted and have a few questions/comments:

  1. Do you think we could support a (much) smaller subset of regexp functionality? I think starting with support for just * would satisfy (almost) all of this specific feature
  2. We could probably do lookups more time-efficiently in the lookup function, particularly if we just support * for now. One option would be to store the table in a tree (possibly a trie)

For an initial implementation, we definitely need to answer (1), but we don't necessarily need to have the most efficient implementation on our first PR. Let me know what you think

arschles avatar Jan 05 '22 19:01 arschles

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Mar 28 '22 21:03 stale[bot]