@@ -28,26 +28,36 @@ import (
2828 "os"
2929 "sort"
3030 "strconv"
31+ "strings"
3132 "sync"
3233
3334 "github.com/fsnotify/fsnotify"
3435 "k8s.io/apimachinery/pkg/types"
36+ "k8s.io/apimachinery/pkg/util/validation"
3537 "sigs.k8s.io/controller-runtime/pkg/log"
3638 "sigs.k8s.io/yaml"
3739
3840 fwkdl "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/datalayer"
3941 fwkplugin "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/plugin"
4042)
4143
42- const PluginType = "file-discovery"
44+ const (
45+ PluginType = "file-discovery"
46+
47+ // EndpointTypeLabel distinguishes pod from cluster endpoints.
48+ EndpointTypeLabel = "llm-d.ai/endpoint-type"
49+ EndpointTypePod = "pod"
50+ EndpointTypeCluster = "cluster"
51+ )
4352
4453// EndpointEntry is the YAML/JSON representation of a single endpoint.
4554type EndpointEntry struct {
46- Name string `json:"name" yaml:"name"`
47- Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
48- Address string `json:"address" yaml:"address"`
49- Port string `json:"port" yaml:"port"`
50- Labels map [string ]string `json:"labels,omitempty" yaml:"labels,omitempty"`
55+ Name string `json:"name" yaml:"name"`
56+ Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
57+ Address string `json:"address" yaml:"address"`
58+ Port string `json:"port" yaml:"port"`
59+ MetricsPort string `json:"metricsPort,omitempty" yaml:"metricsPort,omitempty"`
60+ Labels map [string ]string `json:"labels,omitempty" yaml:"labels,omitempty"`
5161}
5262
5363// EndpointsFile is the top-level structure of the endpoints YAML/JSON file.
@@ -238,9 +248,12 @@ func (f *FileDiscovery) load(notifier fwkdl.DiscoveryNotifier) error {
238248 incoming := make (map [types.NamespacedName ]struct {}, len (ef .Endpoints ))
239249 var errs []error
240250 for _ , e := range ef .Endpoints {
241- if ip := net .ParseIP (e .Address ); ip == nil || ip .To4 () == nil {
242- errs = append (errs , fmt .Errorf ("endpoint %q: invalid IPv4 address %q" , e .Name , e .Address ))
243- continue
251+ ip := net .ParseIP (e .Address )
252+ if ip == nil || ip .To4 () == nil {
253+ if len (validation .IsDNS1123Subdomain (strings .ToLower (e .Address ))) > 0 {
254+ errs = append (errs , fmt .Errorf ("endpoint %q: address %q is not a valid IPv4 or hostname" , e .Name , e .Address ))
255+ continue
256+ }
244257 }
245258 if portNum , err := strconv .Atoi (e .Port ); err != nil || portNum < 1 || portNum > 65535 {
246259 errs = append (errs , fmt .Errorf ("endpoint %q: invalid port %q" , e .Name , e .Port ))
@@ -250,13 +263,32 @@ func (f *FileDiscovery) load(notifier fwkdl.DiscoveryNotifier) error {
250263 if ns == "" {
251264 ns = "default"
252265 }
266+ podName := e .Name
267+ if ip == nil {
268+ podName = ""
269+ }
270+ mPort := e .Port
271+ if e .MetricsPort != "" {
272+ mPort = e .MetricsPort
273+ }
274+ labels := e .Labels
275+ if labels == nil {
276+ labels = make (map [string ]string )
277+ }
278+ if v := labels [EndpointTypeLabel ]; v != EndpointTypePod && v != EndpointTypeCluster {
279+ if ip == nil {
280+ labels [EndpointTypeLabel ] = EndpointTypeCluster
281+ } else {
282+ labels [EndpointTypeLabel ] = EndpointTypePod
283+ }
284+ }
253285 meta := & fwkdl.EndpointMetadata {
254286 NamespacedName : types.NamespacedName {Name : e .Name , Namespace : ns },
255- PodName : e . Name ,
287+ PodName : podName ,
256288 Address : e .Address ,
257289 Port : e .Port ,
258- MetricsHost : net .JoinHostPort (e .Address , e . Port ),
259- Labels : e . Labels ,
290+ MetricsHost : net .JoinHostPort (e .Address , mPort ),
291+ Labels : labels ,
260292 }
261293 incoming [meta .NamespacedName ] = struct {}{}
262294 notifier .Upsert (meta )
0 commit comments