@@ -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,11 @@ 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" , "s|ISTIO_GATEWAY=.*|ISTIO_GATEWAY=istio-system/istio-ingressgateway|" , "config/components/istio/params.env" )
103+ _ , err = utils .Run (cmd )
104+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
105+
101106 cmd = exec .Command ("make" , "deploy" , fmt .Sprintf ("IMG=%s" , controllerImage ))
102107 _ , err = utils .Run (cmd )
103108 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
@@ -298,7 +303,7 @@ var _ = Describe("controller", Ordered, func() {
298303 curlService := func () error {
299304 // NOTE: this command should exit with a non-zero status code if the HTTP status code is >= 400
300305 cmd := exec .Command ("kubectl" , "run" ,
301- "tmp-curl" , "-n" , workspaceNamespace ,
306+ "tmp-curl" , "-n" , workspaceNamespace , "--labels" , "sidecar.istio.io/inject=false" ,
302307 "--attach" , "--command" , fmt .Sprintf ("--image=%s" , curlImage ), "--rm" , "--restart=Never" , "--" ,
303308 "curl" , "-sSL" , "-o" , "/dev/null" , "--fail-with-body" , serviceEndpoint ,
304309 )
@@ -307,6 +312,60 @@ var _ = Describe("controller", Ordered, func() {
307312 }
308313 Eventually (curlService , timeout , interval ).Should (Succeed ())
309314
315+ By ("validating that the workspace virtual service was created" )
316+ var workspaceVirtualServiceName string
317+ verifyWorkspaceVirtualService := func (g Gomega ) {
318+ cmd := exec .Command ("kubectl" , "get" , "virtualservices" ,
319+ "-l" , fmt .Sprintf ("notebooks.kubeflow.org/workspace-name=%s" , workspaceName ),
320+ "-n" , workspaceNamespace ,
321+ "-o" , "go-template={{ range .items }}" +
322+ "{{ if not .metadata.deletionTimestamp }}" +
323+ "{{ .metadata.name }}" +
324+ "{{ \" \\ n\" }}{{ end }}{{ end }}" ,
325+ )
326+ vsOutput , err := utils .Run (cmd )
327+ g .Expect (err ).NotTo (HaveOccurred ())
328+
329+ // Ensure only 1 virtual service is found
330+ vsNames := utils .GetNonEmptyLines (vsOutput )
331+ g .Expect (vsNames ).To (HaveLen (1 ), "expected 1 virtual service found" )
332+ workspaceVirtualServiceName = vsNames [0 ]
333+ g .Expect (workspaceVirtualServiceName ).To (ContainSubstring (fmt .Sprintf ("ws-%s" , workspaceName )))
334+ }
335+ Eventually (verifyWorkspaceVirtualService , timeout , interval ).Should (Succeed ())
336+
337+ By ("validating that the workspace virtual service endpoint is reachable via Istio gateway" )
338+ // Start port-forward to istio-ingressgateway service
339+ // The service exposes HTTP on port 80
340+ localPort := "18080"
341+ serviceHTTPPort := "80"
342+ portForwardSpec := fmt .Sprintf ("%s:%s" , localPort , serviceHTTPPort )
343+
344+ pf , err := utils .StartPortForward (istioNamespace , "istio-ingressgateway" , portForwardSpec , 30 * time .Second )
345+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
346+ defer pf .Stop ()
347+
348+ // Give port-forward a moment to stabilize
349+ time .Sleep (2 * time .Second )
350+
351+ // Test the workspace endpoint through the Istio gateway
352+ gatewayEndpoint := fmt .Sprintf ("http://localhost:%s/workspace/connect/%s/%s/%s/lab" ,
353+ localPort , workspaceNamespace , workspaceName , workspacePortId ,
354+ )
355+ _ , _ = fmt .Fprintf (GinkgoWriter , "Testing gateway endpoint: %s\n " , gatewayEndpoint )
356+
357+ testGatewayEndpoint := func () error {
358+ cmd := exec .Command ("curl" , "-sSL" , "-o" , "/dev/null" , "--fail-with-body" , "-w" , "%{http_code}" , gatewayEndpoint )
359+ output , err := utils .Run (cmd )
360+ if err != nil {
361+ return fmt .Errorf ("curl failed: %w (HTTP status: %s)" , err , output )
362+ }
363+ _ , _ = fmt .Fprintf (GinkgoWriter , "Gateway endpoint returned HTTP status: %s\n " , output )
364+ return nil
365+ }
366+ Eventually (testGatewayEndpoint , timeout , interval ).Should (Succeed (),
367+ "Workspace should be reachable through Istio gateway at %s" , gatewayEndpoint )
368+
310369 By ("ensuring in-use imageConfig values cannot be removed from WorkspaceKind" )
311370 removeInUseImageConfig := func () error {
312371 cmd := exec .Command ("kubectl" , "patch" , "workspacekind" , workspaceKindName ,
0 commit comments