@@ -77,19 +77,19 @@ var _ = Describe("controller", Ordered, func() {
7777 _ , _ = utils .Run (cmd ) // ignore errors because namespace may already exist
7878
7979 // TODO: enable Istio injection once we have logic to create VirtualServices during Workspace reconciliation
80- // By("labeling namespaces for Istio injection")
81- // err := utils.LabelNamespaceForIstioInjection(controllerNamespace)
82- // ExpectWithOffset(1, err).NotTo(HaveOccurred())
80+ By ("labeling namespaces for Istio injection" )
81+ err := utils .LabelNamespaceForIstioInjection (controllerNamespace )
82+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
8383
84- // err = utils.LabelNamespaceForIstioInjection(workspaceNamespace)
85- // ExpectWithOffset(1, err).NotTo(HaveOccurred())
84+ err = utils .LabelNamespaceForIstioInjection (workspaceNamespace )
85+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
8686
8787 By ("creating common workspace resources" )
8888 cmd = exec .Command ("kubectl" , "apply" ,
8989 "-k" , filepath .Join (projectDir , "config/samples/common" ),
9090 "-n" , workspaceNamespace ,
9191 )
92- _ , err : = utils .Run (cmd )
92+ _ , err = utils .Run (cmd )
9393 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
9494
9595 By ("installing CRDs" )
@@ -98,6 +98,13 @@ var _ = Describe("controller", Ordered, func() {
9898 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
9999
100100 By ("deploying the workspaces-controller" )
101+ // Update the ISTIO_GATEWAY config to use istio-system/istio-ingressgateway
102+ cmd = exec .Command ("sed" , "-i" ,
103+ "s|ISTIO_GATEWAY=.*|ISTIO_GATEWAY=istio-system/istio-ingressgateway|" ,
104+ "config/components/istio/params.env" )
105+ _ , err = utils .Run (cmd )
106+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
107+
101108 cmd = exec .Command ("make" , "deploy" , fmt .Sprintf ("IMG=%s" , controllerImage ))
102109 _ , err = utils .Run (cmd )
103110 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
@@ -298,7 +305,7 @@ var _ = Describe("controller", Ordered, func() {
298305 curlService := func () error {
299306 // NOTE: this command should exit with a non-zero status code if the HTTP status code is >= 400
300307 cmd := exec .Command ("kubectl" , "run" ,
301- "tmp-curl" , "-n" , workspaceNamespace ,
308+ "tmp-curl" , "-n" , workspaceNamespace , "--labels" , "sidecar.istio.io/inject=false" ,
302309 "--attach" , "--command" , fmt .Sprintf ("--image=%s" , curlImage ), "--rm" , "--restart=Never" , "--" ,
303310 "curl" , "-sSL" , "-o" , "/dev/null" , "--fail-with-body" , serviceEndpoint ,
304311 )
@@ -307,6 +314,60 @@ var _ = Describe("controller", Ordered, func() {
307314 }
308315 Eventually (curlService , timeout , interval ).Should (Succeed ())
309316
317+ By ("validating that the workspace virtual service was created" )
318+ var workspaceVirtualServiceName string
319+ verifyWorkspaceVirtualService := func (g Gomega ) {
320+ cmd := exec .Command ("kubectl" , "get" , "virtualservices" ,
321+ "-l" , fmt .Sprintf ("notebooks.kubeflow.org/workspace-name=%s" , workspaceName ),
322+ "-n" , workspaceNamespace ,
323+ "-o" , "go-template={{ range .items }}" +
324+ "{{ if not .metadata.deletionTimestamp }}" +
325+ "{{ .metadata.name }}" +
326+ "{{ \" \\ n\" }}{{ end }}{{ end }}" ,
327+ )
328+ vsOutput , err := utils .Run (cmd )
329+ g .Expect (err ).NotTo (HaveOccurred ())
330+
331+ // Ensure only 1 virtual service is found
332+ vsNames := utils .GetNonEmptyLines (vsOutput )
333+ g .Expect (vsNames ).To (HaveLen (1 ), "expected 1 virtual service found" )
334+ workspaceVirtualServiceName = vsNames [0 ]
335+ g .Expect (workspaceVirtualServiceName ).To (ContainSubstring (fmt .Sprintf ("ws-%s" , workspaceName )))
336+ }
337+ Eventually (verifyWorkspaceVirtualService , timeout , interval ).Should (Succeed ())
338+
339+ By ("validating that the workspace virtual service endpoint is reachable via Istio gateway" )
340+ // Start port-forward to istio-ingressgateway service
341+ // The service exposes HTTP on port 80
342+ localPort := "18080"
343+ serviceHTTPPort := "80"
344+ portForwardSpec := fmt .Sprintf ("%s:%s" , localPort , serviceHTTPPort )
345+
346+ pf , err := utils .StartPortForward (istioNamespace , "istio-ingressgateway" , portForwardSpec , 30 * time .Second )
347+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
348+ defer pf .Stop ()
349+
350+ // Give port-forward a moment to stabilize
351+ time .Sleep (2 * time .Second )
352+
353+ // Test the workspace endpoint through the Istio gateway
354+ gatewayEndpoint := fmt .Sprintf ("http://localhost:%s/workspace/connect/%s/%s/%s/lab" ,
355+ localPort , workspaceNamespace , workspaceName , workspacePortId ,
356+ )
357+ _ , _ = fmt .Fprintf (GinkgoWriter , "Testing gateway endpoint: %s\n " , gatewayEndpoint )
358+
359+ testGatewayEndpoint := func () error {
360+ cmd := exec .Command ("curl" , "-sSL" , "-o" , "/dev/null" , "--fail-with-body" , "-w" , "%{http_code}" , gatewayEndpoint )
361+ output , err := utils .Run (cmd )
362+ if err != nil {
363+ return fmt .Errorf ("curl failed: %w (HTTP status: %s)" , err , output )
364+ }
365+ _ , _ = fmt .Fprintf (GinkgoWriter , "Gateway endpoint returned HTTP status: %s\n " , output )
366+ return nil
367+ }
368+ Eventually (testGatewayEndpoint , timeout , interval ).Should (Succeed (),
369+ "Workspace should be reachable through Istio gateway at %s" , gatewayEndpoint )
370+
310371 By ("ensuring in-use imageConfig values cannot be removed from WorkspaceKind" )
311372 removeInUseImageConfig := func () error {
312373 cmd := exec .Command ("kubectl" , "patch" , "workspacekind" , workspaceKindName ,
0 commit comments