Nameresolvers: add support for ResolveIDMulti (#3284)

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
Alessandro (Ale) Segala 2024-01-08 10:17:22 -08:00 committed by GitHub
parent c47907d1a5
commit 59858c49fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 22 deletions

View File

@ -16,7 +16,10 @@ package kubernetes
import (
"bytes"
"context"
"fmt"
"net"
"strconv"
"strings"
"text/template"
"github.com/dapr/components-contrib/nameresolution"
@ -30,6 +33,12 @@ const (
TemplateKey = "template"
)
// Compile-time interface assertions
var (
_ nameresolution.Resolver = (*resolver)(nil)
_ nameresolution.ResolverMulti = (*resolver)(nil)
)
func executeTemplateWithResolveRequest(tmpl *template.Template, req nameresolution.ResolveRequest) (string, error) {
var addr bytes.Buffer
if err := tmpl.Execute(&addr, req); err != nil {
@ -91,3 +100,33 @@ func (k *resolver) ResolveID(ctx context.Context, req nameresolution.ResolveRequ
// Dapr requires this formatting for Kubernetes services
return req.ID + "-dapr." + req.Namespace + ".svc." + k.clusterDomain + ":" + strconv.Itoa(req.Port), nil
}
// ResolveIDMulti resolves an app-id to a set of IP addresses in Kubernetes
func (k *resolver) ResolveIDMulti(ctx context.Context, req nameresolution.ResolveRequest) (nameresolution.AddressList, error) {
// First, get the address from ResolveID, which is usually a DNS name
addr, err := k.ResolveID(ctx, req)
if err != nil {
return nil, err
}
// Extract the port if present
var port string
idx := strings.LastIndexByte(addr, ':')
if idx > -1 && (idx+1) < len(addr) {
port = addr[(idx + 1):]
addr = addr[:idx]
}
// Resolve the DNS name for a list of IPv4 or IPv6
ips, err := net.LookupIP(addr)
if err != nil {
return nil, fmt.Errorf("failed to resolve address for '%s': %w", addr, err)
}
// Return a list of IPs + port
res := make(nameresolution.AddressList, len(ips))
for i, ip := range ips {
res[i] = net.JoinHostPort(ip.String(), port)
}
return res, nil
}

View File

@ -15,6 +15,8 @@ package nameresolution
import (
"context"
"math/rand"
"strconv"
)
// Resolver is the interface of name resolver.
@ -24,3 +26,39 @@ type Resolver interface {
// ResolveID resolves name to address.
ResolveID(ctx context.Context, req ResolveRequest) (string, error)
}
// ResolverMulti is an optional interface for name resolvers that can return multiple addresses.
type ResolverMulti interface {
ResolveIDMulti(ctx context.Context, req ResolveRequest) (AddressList, error)
}
// ResolveRequest represents service discovery resolver request.
type ResolveRequest struct {
ID string
Namespace string
Port int
Data map[string]string
}
// CacheKey returns a string that can be used to identify this ResolveRequest in a cache
func (r ResolveRequest) CacheKey() string {
return r.Namespace + "/" + r.ID + "/" + strconv.Itoa(r.Port)
}
// AddressList is a list of addresses resolved by the nameresolver
type AddressList []string
// Pick returns a random address from the list
func (a AddressList) Pick() string {
l := len(a)
switch l {
case 0:
return ""
case 1:
return a[0]
default:
// We use math/rand here as we are just picking a random address, so we don't need a CSPRNG
//nolint:gosec
return a[rand.Intn(l)]
}
}

View File

@ -1,22 +0,0 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nameresolution
// ResolveRequest represents service discovery resolver request.
type ResolveRequest struct {
ID string
Namespace string
Port int
Data map[string]string
}