Skip to content

Commit 8837d5f

Browse files
authored
Ability to configure Raw InferenceGraphs as private (#521)
This adds the possibility to use the `networking.kserve.io/visibility=cluster-local` label to configure an InferenceGraph in Raw mode as private (not exposed). Signed-off-by: Edgar Hernández <[email protected]>
1 parent 0f6b26f commit 8837d5f

File tree

5 files changed

+195
-1
lines changed

5 files changed

+195
-1
lines changed

config/rbac/role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ rules:
117117
- routes
118118
verbs:
119119
- create
120+
- delete
120121
- get
121122
- list
122123
- patch

pkg/controller/v1alpha1/inferencegraph/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ limitations under the License.
1919
// +kubebuilder:rbac:groups=serving.knative.dev,resources=services,verbs=get;list;watch;create;update;patch;delete
2020
// +kubebuilder:rbac:groups=serving.knative.dev,resources=services/finalizers,verbs=get;list;watch;create;update;patch;delete
2121
// +kubebuilder:rbac:groups=serving.knative.dev,resources=services/status,verbs=get;update;patch
22-
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=create;get;update;patch;watch
22+
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=create;get;update;patch;watch;delete
2323
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes/status,verbs=get
2424
package inferencegraph
2525

pkg/controller/v1alpha1/inferencegraph/controller_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"google.golang.org/protobuf/proto"
2828
appsv1 "k8s.io/api/apps/v1"
2929
v1 "k8s.io/api/core/v1"
30+
"k8s.io/apimachinery/pkg/api/errors"
3031
"k8s.io/apimachinery/pkg/api/resource"
3132
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3233
"k8s.io/apimachinery/pkg/types"
@@ -696,6 +697,149 @@ var _ = Describe("Inference Graph controller test", func() {
696697
return inferenceGraphSubmitted.Status.URL.Host
697698
}, timeout, interval).Should(Equal(osRoute.Status.Ingress[0].Host))
698699
})
700+
701+
It("Should not create ingress when cluster-local visibility is configured", func() {
702+
By("By creating a new InferenceGraph")
703+
var configMap = &v1.ConfigMap{
704+
ObjectMeta: metav1.ObjectMeta{
705+
Name: constants.InferenceServiceConfigMapName,
706+
Namespace: constants.KServeNamespace,
707+
},
708+
Data: configs,
709+
}
710+
Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred())
711+
defer func() { _ = k8sClient.Delete(context.TODO(), configMap) }()
712+
graphName := "igraw-private"
713+
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: graphName, Namespace: "default"}}
714+
var serviceKey = expectedRequest.NamespacedName
715+
ctx := context.Background()
716+
ig := &v1alpha1.InferenceGraph{
717+
ObjectMeta: metav1.ObjectMeta{
718+
Name: serviceKey.Name,
719+
Namespace: serviceKey.Namespace,
720+
Annotations: map[string]string{
721+
"serving.kserve.io/deploymentMode": string(constants.RawDeployment),
722+
},
723+
Labels: map[string]string{
724+
constants.NetworkVisibility: constants.ClusterLocalVisibility,
725+
},
726+
},
727+
Spec: v1alpha1.InferenceGraphSpec{
728+
Nodes: map[string]v1alpha1.InferenceRouter{
729+
v1alpha1.GraphRootNodeName: {
730+
RouterType: v1alpha1.Sequence,
731+
Steps: []v1alpha1.InferenceStep{
732+
{
733+
InferenceTarget: v1alpha1.InferenceTarget{
734+
ServiceURL: "http://someservice.exmaple.com",
735+
},
736+
},
737+
},
738+
},
739+
},
740+
},
741+
}
742+
Expect(k8sClient.Create(ctx, ig)).Should(Succeed())
743+
defer func() { _ = k8sClient.Delete(ctx, ig) }()
744+
745+
// The OpenShift route must not be created
746+
actualK8sDeploymentCreated := &appsv1.Deployment{}
747+
Eventually(func() error {
748+
return k8sClient.Get(ctx, serviceKey, actualK8sDeploymentCreated)
749+
}, timeout, interval).Should(Succeed())
750+
actualK8sDeploymentCreated.Status.Conditions = []appsv1.DeploymentCondition{
751+
{Type: appsv1.DeploymentAvailable},
752+
}
753+
Expect(k8sClient.Status().Update(ctx, actualK8sDeploymentCreated)).Should(Succeed())
754+
osRoute := osv1.Route{}
755+
Consistently(func() error {
756+
osRouteKey := types.NamespacedName{Name: ig.GetName() + "-route", Namespace: ig.GetNamespace()}
757+
return k8sClient.Get(ctx, osRouteKey, &osRoute)
758+
}, timeout, interval).Should(WithTransform(errors.IsNotFound, BeTrue()))
759+
760+
// The InferenceGraph should have a cluster-internal hostname
761+
Eventually(func() string {
762+
_ = k8sClient.Get(ctx, serviceKey, ig)
763+
return ig.Status.URL.Host
764+
}, timeout, interval).Should(Equal(fmt.Sprintf("%s.%s.svc.cluster.local", graphName, "default")))
765+
})
766+
767+
It("Should reconfigure InferenceGraph as private when cluster-local visibility is configured", func() {
768+
By("By creating a new InferenceGraph")
769+
var configMap = &v1.ConfigMap{
770+
ObjectMeta: metav1.ObjectMeta{
771+
Name: constants.InferenceServiceConfigMapName,
772+
Namespace: constants.KServeNamespace,
773+
},
774+
Data: configs,
775+
}
776+
Expect(k8sClient.Create(context.TODO(), configMap)).NotTo(HaveOccurred())
777+
defer func() { _ = k8sClient.Delete(context.TODO(), configMap) }()
778+
graphName := "igraw-exposed-to-private"
779+
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: graphName, Namespace: "default"}}
780+
var serviceKey = expectedRequest.NamespacedName
781+
ctx := context.Background()
782+
ig := &v1alpha1.InferenceGraph{
783+
ObjectMeta: metav1.ObjectMeta{
784+
Name: serviceKey.Name,
785+
Namespace: serviceKey.Namespace,
786+
Annotations: map[string]string{
787+
"serving.kserve.io/deploymentMode": string(constants.RawDeployment),
788+
},
789+
},
790+
Spec: v1alpha1.InferenceGraphSpec{
791+
Nodes: map[string]v1alpha1.InferenceRouter{
792+
v1alpha1.GraphRootNodeName: {
793+
RouterType: v1alpha1.Sequence,
794+
Steps: []v1alpha1.InferenceStep{
795+
{
796+
InferenceTarget: v1alpha1.InferenceTarget{
797+
ServiceURL: "http://someservice.exmaple.com",
798+
},
799+
},
800+
},
801+
},
802+
},
803+
},
804+
}
805+
Expect(k8sClient.Create(ctx, ig)).Should(Succeed())
806+
defer func() { _ = k8sClient.Delete(ctx, ig) }()
807+
808+
// Wait the OpenShift route to be created
809+
actualK8sDeploymentCreated := &appsv1.Deployment{}
810+
Eventually(func() error {
811+
return k8sClient.Get(ctx, serviceKey, actualK8sDeploymentCreated)
812+
}, timeout, interval).Should(Succeed())
813+
actualK8sDeploymentCreated.Status.Conditions = []appsv1.DeploymentCondition{
814+
{Type: appsv1.DeploymentAvailable},
815+
}
816+
Expect(k8sClient.Status().Update(ctx, actualK8sDeploymentCreated)).Should(Succeed())
817+
osRoute := osv1.Route{}
818+
Eventually(func() error {
819+
osRouteKey := types.NamespacedName{Name: ig.GetName() + "-route", Namespace: ig.GetNamespace()}
820+
return k8sClient.Get(ctx, osRouteKey, &osRoute)
821+
}, timeout, interval).Should(Succeed())
822+
823+
// Reconfigure as private
824+
Expect(k8sClient.Get(ctx, serviceKey, ig)).Should(Succeed())
825+
if ig.Labels == nil {
826+
ig.Labels = map[string]string{}
827+
}
828+
ig.Labels[constants.NetworkVisibility] = constants.ClusterLocalVisibility
829+
Expect(k8sClient.Update(ctx, ig)).Should(Succeed())
830+
831+
// The OpenShift route should be deleted
832+
Eventually(func() error {
833+
osRouteKey := types.NamespacedName{Name: ig.GetName() + "-route", Namespace: ig.GetNamespace()}
834+
return k8sClient.Get(ctx, osRouteKey, &osRoute)
835+
}).Should(WithTransform(errors.IsNotFound, BeTrue()))
836+
837+
// The InferenceGraph should have a cluster-internal hostname
838+
Eventually(func() string {
839+
_ = k8sClient.Get(ctx, serviceKey, ig)
840+
return ig.Status.URL.Host
841+
}, timeout, interval).Should(Equal(fmt.Sprintf("%s.%s.svc.cluster.local", graphName, "default")))
842+
})
699843
})
700844

701845
Context("When creating an InferenceGraph in Serverless mode", func() {

pkg/controller/v1alpha1/inferencegraph/openshift_route_reconciler.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
Copyright 2023 The KServe Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
package inferencegraph
218

319
import (
@@ -10,11 +26,13 @@ import (
1026
"k8s.io/apimachinery/pkg/runtime"
1127
"k8s.io/apimachinery/pkg/types"
1228
"k8s.io/apimachinery/pkg/util/intstr"
29+
"knative.dev/pkg/network"
1330
"sigs.k8s.io/controller-runtime/pkg/client"
1431
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1532
ctrlLog "sigs.k8s.io/controller-runtime/pkg/log"
1633

1734
"github.com/kserve/kserve/pkg/apis/serving/v1alpha1"
35+
"github.com/kserve/kserve/pkg/constants"
1836
)
1937

2038
type OpenShiftRouteReconciler struct {
@@ -41,6 +59,21 @@ func (r *OpenShiftRouteReconciler) Reconcile(ctx context.Context, inferenceGraph
4159
return "", err
4260
}
4361

62+
if val, ok := inferenceGraph.Labels[constants.NetworkVisibility]; ok && val == constants.ClusterLocalVisibility {
63+
privateHost := network.GetServiceHostname(inferenceGraph.GetName(), inferenceGraph.GetNamespace())
64+
// The IG is private. Remove the route, if needed.
65+
if len(actualRoute.Name) != 0 {
66+
logger.Info("Deleting OpenShift Route for InferenceGraph", "namespace", desiredRoute.Namespace, "name", desiredRoute.Name)
67+
err = r.Client.Delete(ctx, &actualRoute)
68+
if err != nil {
69+
return privateHost, err
70+
}
71+
}
72+
73+
// Return private hostname.
74+
return privateHost, nil
75+
}
76+
4477
if len(actualRoute.Name) == 0 {
4578
logger.Info("Creating a new OpenShift Route for InferenceGraph", "namespace", desiredRoute.Namespace, "name", desiredRoute.Name)
4679
err = r.Client.Create(ctx, &desiredRoute)

pkg/webhook/validation/inferenceservice/inferenceservice_webhook_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
Copyright 2023 The KServe Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
package inferenceservice
218

319
import (

0 commit comments

Comments
 (0)