Skip to content

Commit 5da9581

Browse files
zdtswgoogs1025
authored andcommitted
fix: github action runner not exist (#477)
- ubuntu-20.04 is already deprecated - use ubunut-latest to dynamically use latest version (cherry picked from commit 80ac25b) Signed-off-by: Wen Zhou <wenzhou@redhat.com> Signed-off-by: CYJiang <googs1025@gmail.com>
1 parent 3e54797 commit 5da9581

File tree

2 files changed

+69
-15
lines changed

2 files changed

+69
-15
lines changed

.github/workflows/re-run-action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
rerun_pr_tests:
99
name: rerun_pr_tests
1010
if: ${{ github.event.issue.pull_request }}
11-
runs-on: ubuntu-20.04
11+
runs-on: ubuntu-latest
1212
steps:
1313
- uses: estroz/rerun-actions@main
1414
with:

pkg/sidecar/proxy/allowlist.go

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ import (
2424
"time"
2525

2626
"github.com/go-logr/logr"
27+
"k8s.io/apimachinery/pkg/api/errors"
2728
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2829
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2930
"k8s.io/apimachinery/pkg/labels"
3031
"k8s.io/apimachinery/pkg/runtime"
3132
"k8s.io/apimachinery/pkg/runtime/schema"
3233
"k8s.io/apimachinery/pkg/watch"
34+
"k8s.io/client-go/discovery"
3335
"k8s.io/client-go/dynamic"
3436
"k8s.io/client-go/tools/cache"
3537
"k8s.io/client-go/tools/clientcmd"
@@ -38,12 +40,28 @@ import (
3840
)
3941

4042
const (
41-
inferencePoolGroup = "inference.networking.x-k8s.io"
42-
inferencePoolVersion = "v1alpha2"
4343
inferencePoolResource = "inferencepools"
4444
resyncPeriod = 30 * time.Second
4545
)
4646

47+
// candidateGVRs in order of preference
48+
//
49+
// We maintain a prioritized list of GroupVersionResource (GVR) candidates to support
50+
// environments where either the legacy or the new InferencePool CRD may be installed:
51+
//
52+
// 1. inference.networking.k8s.io/v1 ← Preferred (new official API group)
53+
// 2. inference.networking.x-k8s.io/v1alpha2 ← Fallback (legacy experimental API group)
54+
55+
// The validator automatically detects which API is available by using the Kubernetes
56+
// discovery API, selecting the first supported GVR in this list.
57+
//
58+
// This approach aligns with upstream Ingress Gateway (IGW) behavior, which also supports
59+
// both API versions concurrently (see issue #462).
60+
var candidateGVRs = []schema.GroupVersionResource{
61+
{Group: "inference.networking.k8s.io", Version: "v1", Resource: inferencePoolResource},
62+
{Group: "inference.networking.x-k8s.io", Version: "v1alpha2", Resource: inferencePoolResource},
63+
}
64+
4765
// AllowlistValidator manages allowed prefill targets based on InferencePool resources
4866
type AllowlistValidator struct {
4967
logger logr.Logger
@@ -52,6 +70,8 @@ type AllowlistValidator struct {
5270
poolName string
5371
enabled bool
5472

73+
gvr schema.GroupVersionResource // detected GVR
74+
5575
// allowedTargets maps hostport -> bool for allowed prefill targets
5676
allowedTargets set.Set[string]
5777
allowedTargetsMu sync.RWMutex
@@ -87,6 +107,27 @@ func NewAllowlistValidator(enabled bool, namespace string, poolName string) (*Al
87107
return nil, fmt.Errorf("failed to create Kubernetes dynamic client: %w", err)
88108
}
89109

110+
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
111+
if err != nil {
112+
return nil, fmt.Errorf("failed to create discovery client: %w", err)
113+
}
114+
115+
var detectedGVR schema.GroupVersionResource
116+
for _, gvr := range candidateGVRs {
117+
supported, err := isGVRSupported(discoveryClient, gvr)
118+
if err != nil {
119+
return nil, fmt.Errorf("error checking GVR %s: %w", gvr.String(), err)
120+
}
121+
if supported {
122+
detectedGVR = gvr
123+
break
124+
}
125+
}
126+
127+
if detectedGVR.Empty() {
128+
return nil, fmt.Errorf("no supported InferencePool API found; tried: %v", candidateGVRs)
129+
}
130+
90131
return &AllowlistValidator{
91132
enabled: true,
92133
dynamicClient: dynamicClient,
@@ -99,32 +140,45 @@ func NewAllowlistValidator(enabled bool, namespace string, poolName string) (*Al
99140
}, nil
100141
}
101142

143+
func isGVRSupported(discoveryClient discovery.DiscoveryInterface, gvr schema.GroupVersionResource) (bool, error) {
144+
apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(gvr.GroupVersion().String())
145+
if err != nil {
146+
// If the group/version doesn't exist, Kubernetes returns a "NotFound" error
147+
if errors.IsNotFound(err) {
148+
return false, nil // GroupVersion not supported
149+
}
150+
return false, fmt.Errorf("failed to discover resources for %s: %w", gvr.String(), err)
151+
}
152+
153+
for _, resource := range apiResourceList.APIResources {
154+
if resource.Name == gvr.Resource {
155+
return true, nil
156+
}
157+
}
158+
return false, nil
159+
}
160+
102161
// Start begins watching InferencePool resources and managing the allowlist
103162
func (av *AllowlistValidator) Start(ctx context.Context) error {
104163
if !av.enabled {
105164
return nil
106165
}
107166

108167
av.logger = log.FromContext(ctx).WithName("allowlist-validator")
109-
av.logger.Info("starting SSRF protection allowlist validator", "namespace", av.namespace, "poolName", av.poolName)
110-
111-
gvr := schema.GroupVersionResource{
112-
Group: inferencePoolGroup,
113-
Version: inferencePoolVersion,
114-
Resource: inferencePoolResource,
115-
}
168+
av.logger.Info("starting SSRF protection allowlist validator",
169+
"namespace", av.namespace, "poolName", av.poolName, "gvr", av.gvr.String())
116170

117171
// Create informer for the specific InferencePool resource
118172
lw := &cache.ListWatch{
119-
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
173+
ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
120174
// List with field selector to get only the specific InferencePool
121175
options.FieldSelector = "metadata.name=" + av.poolName
122-
return av.dynamicClient.Resource(gvr).Namespace(av.namespace).List(ctx, options)
176+
return av.dynamicClient.Resource(av.gvr).Namespace(av.namespace).List(ctx, options)
123177
},
124-
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
178+
WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
125179
// Watch the specific InferencePool by name using field selector
126180
options.FieldSelector = "metadata.name=" + av.poolName
127-
return av.dynamicClient.Resource(gvr).Namespace(av.namespace).Watch(ctx, options)
181+
return av.dynamicClient.Resource(av.gvr).Namespace(av.namespace).Watch(ctx, options)
128182
},
129183
}
130184

@@ -142,7 +196,7 @@ func (av *AllowlistValidator) Start(ctx context.Context) error {
142196

143197
// Wait for cache sync
144198
if !cache.WaitForCacheSync(av.stopCh, av.poolInformer.HasSynced) {
145-
return fmt.Errorf("failed to sync InferencePool cache within timeout (check RBAC permissions for inferencepools.%s and that pool '%s' exists)", inferencePoolGroup, av.poolName)
199+
return fmt.Errorf("failed to sync InferencePool cache within timeout (check RBAC permissions for inferencepools.%s and that pool '%s' exists)", av.gvr.Group, av.poolName)
146200
}
147201

148202
av.logger.Info("allowlist validator started successfully")

0 commit comments

Comments
 (0)