From a17464bdd3cc7c660f9405bf587946be873bbe66 Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Sun, 16 Feb 2025 09:43:46 +0200 Subject: [PATCH 1/6] Add missing ports field to workspace model Signed-off-by: Yehudit Kerido --- .../internal/models/workspaces/funcs.go | 34 +++++++++++++++++++ .../internal/models/workspaces/types.go | 7 ++++ 2 files changed, 41 insertions(+) diff --git a/workspaces/backend/internal/models/workspaces/funcs.go b/workspaces/backend/internal/models/workspaces/funcs.go index 23288c070..388893639 100644 --- a/workspaces/backend/internal/models/workspaces/funcs.go +++ b/workspaces/backend/internal/models/workspaces/funcs.go @@ -128,6 +128,39 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef return workspaceModel } +func buildPortsList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) []ImagePort { + var ports []ImagePort + + // Return an empty list if wsk is nil. + if !wskExists(wsk) { + return ports + } + + // Get the image configuration from the WorkspaceKind's PodTemplate options. + imageConfig := wsk.Spec.PodTemplate.Options.ImageConfig + + for _, val := range imageConfig.Values { + if len(val.Spec.Ports) == 0 { + continue + } + firstPort := val.Spec.Ports[0] + portStr := fmt.Sprintf("%d", firstPort.Port) + id := firstPort.Id + displayName := firstPort.DisplayName + if displayName == "" { + displayName = val.Id + } + imagePort := ImagePort{ + ID: id, + DisplayName: displayName, + Port: portStr, + } + ports = append(ports, imagePort) + } + + return ports +} + func wskExists(wsk *kubefloworgv1beta1.WorkspaceKind) bool { return wsk != nil && wsk.UID != "" } @@ -218,6 +251,7 @@ func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1. Current: currentImageConfig, Desired: desiredImageConfig, RedirectChain: redirectChain, + Ports: buildPortsList(ws, wsk), } } diff --git a/workspaces/backend/internal/models/workspaces/types.go b/workspaces/backend/internal/models/workspaces/types.go index 752965b68..dbc06545f 100644 --- a/workspaces/backend/internal/models/workspaces/types.go +++ b/workspaces/backend/internal/models/workspaces/types.go @@ -84,6 +84,13 @@ type ImageConfig struct { Current OptionInfo `json:"current"` Desired *OptionInfo `json:"desired,omitempty"` RedirectChain []RedirectStep `json:"redirectChain,omitempty"` + Ports []ImagePort `json:"ports,omitempty"` +} + +type ImagePort struct { + ID string `json:"id"` + DisplayName string `json:"display_name"` + Port string `json:"port"` } type PodConfig struct { From ddd6ebbe1dc9a37af132b167e5abd47138e5ec81 Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Wed, 19 Feb 2025 10:01:54 +0200 Subject: [PATCH 2/6] Add missing ports field to workspace model Signed-off-by: Yehudit Kerido --- workspaces/backend/internal/models/workspaces/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/backend/internal/models/workspaces/types.go b/workspaces/backend/internal/models/workspaces/types.go index dbc06545f..fc62eefbd 100644 --- a/workspaces/backend/internal/models/workspaces/types.go +++ b/workspaces/backend/internal/models/workspaces/types.go @@ -89,7 +89,7 @@ type ImageConfig struct { type ImagePort struct { ID string `json:"id"` - DisplayName string `json:"display_name"` + DisplayName string `json:"displayName"` Port string `json:"port"` } From 82b435d1c24c0f226c2ba2efd8f2d0486a80685a Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Mon, 24 Feb 2025 15:21:58 +0200 Subject: [PATCH 3/6] Add services field to workspace model Signed-off-by: Yehudit Kerido --- .../internal/models/workspaces/funcs.go | 27 ++++++++++--------- .../internal/models/workspaces/types.go | 11 +++++--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/workspaces/backend/internal/models/workspaces/funcs.go b/workspaces/backend/internal/models/workspaces/funcs.go index 388893639..df87f760b 100644 --- a/workspaces/backend/internal/models/workspaces/funcs.go +++ b/workspaces/backend/internal/models/workspaces/funcs.go @@ -18,6 +18,7 @@ package workspaces import ( "fmt" + "path" kubefloworgv1beta1 "github.com/kubeflow/notebooks/workspaces/controller/api/v1beta1" "k8s.io/utils/ptr" @@ -124,16 +125,17 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef // https://github.com/kubeflow/notebooks/issues/38 LastProbe: nil, }, + Services: buildServicesList(ws, wsk), } return workspaceModel } -func buildPortsList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) []ImagePort { - var ports []ImagePort +func buildServicesList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) []Service { + //nolint:prealloc + var services []Service - // Return an empty list if wsk is nil. if !wskExists(wsk) { - return ports + return services } // Get the image configuration from the WorkspaceKind's PodTemplate options. @@ -145,20 +147,22 @@ func buildPortsList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.Wo } firstPort := val.Spec.Ports[0] portStr := fmt.Sprintf("%d", firstPort.Port) - id := firstPort.Id displayName := firstPort.DisplayName if displayName == "" { displayName = val.Id } - imagePort := ImagePort{ - ID: id, - DisplayName: displayName, - Port: portStr, + basePath := "/workspace" + notebookPath := path.Join(basePath, ws.Namespace, ws.Name, portStr) + service := Service{ + HttpService: &HttpService{ + DisplayName: displayName, + HttpPath: notebookPath, + }, } - ports = append(ports, imagePort) + services = append(services, service) } - return ports + return services } func wskExists(wsk *kubefloworgv1beta1.WorkspaceKind) bool { @@ -251,7 +255,6 @@ func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1. Current: currentImageConfig, Desired: desiredImageConfig, RedirectChain: redirectChain, - Ports: buildPortsList(ws, wsk), } } diff --git a/workspaces/backend/internal/models/workspaces/types.go b/workspaces/backend/internal/models/workspaces/types.go index fc62eefbd..ccd61cbc6 100644 --- a/workspaces/backend/internal/models/workspaces/types.go +++ b/workspaces/backend/internal/models/workspaces/types.go @@ -29,6 +29,7 @@ type Workspace struct { StateMessage string `json:"stateMessage"` PodTemplate PodTemplate `json:"podTemplate"` Activity Activity `json:"activity"` + Services []Service `json:"services,omitempty"` } type WorkspaceState string @@ -84,13 +85,15 @@ type ImageConfig struct { Current OptionInfo `json:"current"` Desired *OptionInfo `json:"desired,omitempty"` RedirectChain []RedirectStep `json:"redirectChain,omitempty"` - Ports []ImagePort `json:"ports,omitempty"` } -type ImagePort struct { - ID string `json:"id"` +type Service struct { + HttpService *HttpService `json:"httpService,omitempty"` +} + +type HttpService struct { DisplayName string `json:"displayName"` - Port string `json:"port"` + HttpPath string `json:"httpPath"` } type PodConfig struct { From 9ff248355f3c41a4287e8c136383b9f7a9e83853 Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Thu, 27 Feb 2025 16:28:14 +0200 Subject: [PATCH 4/6] Add services field to workspace model Signed-off-by: Yehudit Kerido --- .../internal/models/workspaces/funcs.go | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/workspaces/backend/internal/models/workspaces/funcs.go b/workspaces/backend/internal/models/workspaces/funcs.go index df87f760b..3427c8c77 100644 --- a/workspaces/backend/internal/models/workspaces/funcs.go +++ b/workspaces/backend/internal/models/workspaces/funcs.go @@ -131,37 +131,42 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef } func buildServicesList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) []Service { - //nolint:prealloc - var services []Service - if !wskExists(wsk) { - return services + return nil } - // Get the image configuration from the WorkspaceKind's PodTemplate options. imageConfig := wsk.Spec.PodTemplate.Options.ImageConfig + basePath := "/workspace" + namespacePath := path.Join(basePath, ws.Namespace, ws.Name) + + services := make([]Service, 0, len(imageConfig.Values)) for _, val := range imageConfig.Values { - if len(val.Spec.Ports) == 0 { - continue - } - firstPort := val.Spec.Ports[0] - portStr := fmt.Sprintf("%d", firstPort.Port) - displayName := firstPort.DisplayName + services = append(services, extractServices(&val, namespacePath)...) + } + return services +} + +func extractServices(val *kubefloworgv1beta1.ImageConfigValue, namespacePath string) []Service { + if len(val.Spec.Ports) == 0 { + return []Service{} + } + + services := make([]Service, 0, len(val.Spec.Ports)) + + for _, port := range val.Spec.Ports { + displayName := port.DisplayName if displayName == "" { displayName = val.Id } - basePath := "/workspace" - notebookPath := path.Join(basePath, ws.Namespace, ws.Name, portStr) service := Service{ HttpService: &HttpService{ DisplayName: displayName, - HttpPath: notebookPath, + HttpPath: path.Join(namespacePath, fmt.Sprintf("%d", port.Port)), }, } services = append(services, service) } - return services } From 63af6312706aac2dc38c7f4d41832792ccc67705 Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Thu, 27 Feb 2025 18:29:29 +0200 Subject: [PATCH 5/6] Add services field to workspace model Signed-off-by: Yehudit Kerido --- workspaces/backend/internal/models/workspaces/funcs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/backend/internal/models/workspaces/funcs.go b/workspaces/backend/internal/models/workspaces/funcs.go index 3427c8c77..b5d96b0c9 100644 --- a/workspaces/backend/internal/models/workspaces/funcs.go +++ b/workspaces/backend/internal/models/workspaces/funcs.go @@ -162,7 +162,7 @@ func extractServices(val *kubefloworgv1beta1.ImageConfigValue, namespacePath str service := Service{ HttpService: &HttpService{ DisplayName: displayName, - HttpPath: path.Join(namespacePath, fmt.Sprintf("%d", port.Port)), + HttpPath: path.Join(namespacePath, port.Id), }, } services = append(services, service) From 4e91e38bb6916390a7b788bb812bb270752557c8 Mon Sep 17 00:00:00 2001 From: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:04:23 -0800 Subject: [PATCH 6/6] mathew updates: 1 Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com> --- .../internal/models/workspaces/funcs.go | 82 ++++++++----------- .../internal/models/workspaces/types.go | 20 ++--- 2 files changed, 44 insertions(+), 58 deletions(-) diff --git a/workspaces/backend/internal/models/workspaces/funcs.go b/workspaces/backend/internal/models/workspaces/funcs.go index b5d96b0c9..d07964d49 100644 --- a/workspaces/backend/internal/models/workspaces/funcs.go +++ b/workspaces/backend/internal/models/workspaces/funcs.go @@ -18,7 +18,6 @@ package workspaces import ( "fmt" - "path" kubefloworgv1beta1 "github.com/kubeflow/notebooks/workspaces/controller/api/v1beta1" "k8s.io/utils/ptr" @@ -90,6 +89,9 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef } } + imageConfigModel, imageConfigValue := buildImageConfig(ws, wsk) + podConfigModel, _ := buildPodConfig(ws, wsk) + workspaceModel := Workspace{ Name: ws.Name, Namespace: ws.Namespace, @@ -114,8 +116,8 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef Data: dataVolumes, }, Options: PodTemplateOptions{ - ImageConfig: buildImageConfig(ws, wsk), - PodConfig: buildPodConfig(ws, wsk), + ImageConfig: imageConfigModel, + PodConfig: podConfigModel, }, }, Activity: Activity{ @@ -125,51 +127,11 @@ func NewWorkspaceModelFromWorkspace(ws *kubefloworgv1beta1.Workspace, wsk *kubef // https://github.com/kubeflow/notebooks/issues/38 LastProbe: nil, }, - Services: buildServicesList(ws, wsk), + Services: buildServices(ws, imageConfigValue), } return workspaceModel } -func buildServicesList(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) []Service { - if !wskExists(wsk) { - return nil - } - - imageConfig := wsk.Spec.PodTemplate.Options.ImageConfig - basePath := "/workspace" - namespacePath := path.Join(basePath, ws.Namespace, ws.Name) - - services := make([]Service, 0, len(imageConfig.Values)) - - for _, val := range imageConfig.Values { - services = append(services, extractServices(&val, namespacePath)...) - } - return services -} - -func extractServices(val *kubefloworgv1beta1.ImageConfigValue, namespacePath string) []Service { - if len(val.Spec.Ports) == 0 { - return []Service{} - } - - services := make([]Service, 0, len(val.Spec.Ports)) - - for _, port := range val.Spec.Ports { - displayName := port.DisplayName - if displayName == "" { - displayName = val.Id - } - service := Service{ - HttpService: &HttpService{ - DisplayName: displayName, - HttpPath: path.Join(namespacePath, port.Id), - }, - } - services = append(services, service) - } - return services -} - func wskExists(wsk *kubefloworgv1beta1.WorkspaceKind) bool { return wsk != nil && wsk.UID != "" } @@ -193,7 +155,7 @@ func buildHomeVolume(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.W } } -func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) ImageConfig { +func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) (ImageConfig, *kubefloworgv1beta1.ImageConfigValue) { // create a map of image configs from the WorkspaceKind for easy lookup by ID // NOTE: we can only build this map if the WorkspaceKind exists, otherwise it will be empty imageConfigMap := make(map[string]kubefloworgv1beta1.ImageConfigValue) @@ -205,6 +167,7 @@ func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1. } // get the current image config + var currentImageConfigValue *kubefloworgv1beta1.ImageConfigValue currentImageConfig := OptionInfo{ Id: ws.Spec.PodTemplate.Options.ImageConfig, DisplayName: UnknownImageConfig, @@ -212,6 +175,7 @@ func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1. Labels: nil, } if cfg, ok := imageConfigMap[currentImageConfig.Id]; ok { + currentImageConfigValue = &cfg currentImageConfig.DisplayName = cfg.Spawner.DisplayName currentImageConfig.Description = ptr.Deref(cfg.Spawner.Description, "") currentImageConfig.Labels = buildOptionLabels(cfg.Spawner.Labels) @@ -260,10 +224,10 @@ func buildImageConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1. Current: currentImageConfig, Desired: desiredImageConfig, RedirectChain: redirectChain, - } + }, currentImageConfigValue } -func buildPodConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) PodConfig { +func buildPodConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.WorkspaceKind) (PodConfig, *kubefloworgv1beta1.PodConfigValue) { // create a map of pod configs from the WorkspaceKind for easy lookup by ID // NOTE: we can only build this map if the WorkspaceKind exists, otherwise it will be empty podConfigMap := make(map[string]kubefloworgv1beta1.PodConfigValue) @@ -275,6 +239,7 @@ func buildPodConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.Wo } // get the current pod config + var currentPodConfigValue *kubefloworgv1beta1.PodConfigValue currentPodConfig := OptionInfo{ Id: ws.Spec.PodTemplate.Options.PodConfig, DisplayName: UnknownPodConfig, @@ -282,6 +247,7 @@ func buildPodConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.Wo Labels: nil, } if cfg, ok := podConfigMap[currentPodConfig.Id]; ok { + currentPodConfigValue = &cfg currentPodConfig.DisplayName = cfg.Spawner.DisplayName currentPodConfig.Description = ptr.Deref(cfg.Spawner.Description, "") currentPodConfig.Labels = buildOptionLabels(cfg.Spawner.Labels) @@ -330,7 +296,7 @@ func buildPodConfig(ws *kubefloworgv1beta1.Workspace, wsk *kubefloworgv1beta1.Wo Current: currentPodConfig, Desired: desiredPodConfig, RedirectChain: redirectChain, - } + }, currentPodConfigValue } func buildOptionLabels(labels []kubefloworgv1beta1.OptionSpawnerLabel) []OptionLabel { @@ -364,3 +330,23 @@ func buildRedirectMessage(msg *kubefloworgv1beta1.RedirectMessage) *RedirectMess Level: messageLevel, } } + +func buildServices(ws *kubefloworgv1beta1.Workspace, imageConfigValue *kubefloworgv1beta1.ImageConfigValue) []Service { + if imageConfigValue == nil { + return nil + } + + services := make([]Service, len(imageConfigValue.Spec.Ports)) + for i := range imageConfigValue.Spec.Ports { + port := imageConfigValue.Spec.Ports[i] + switch port.Protocol { //nolint:gocritic + case kubefloworgv1beta1.ImagePortProtocolHTTP: + services[i].HttpService = &HttpService{ + DisplayName: port.DisplayName, + HttpPath: fmt.Sprintf("/workspace/%s/%s/%s/", ws.Namespace, ws.Name, port.Id), + } + } + } + + return services +} diff --git a/workspaces/backend/internal/models/workspaces/types.go b/workspaces/backend/internal/models/workspaces/types.go index ccd61cbc6..92d52f076 100644 --- a/workspaces/backend/internal/models/workspaces/types.go +++ b/workspaces/backend/internal/models/workspaces/types.go @@ -29,7 +29,7 @@ type Workspace struct { StateMessage string `json:"stateMessage"` PodTemplate PodTemplate `json:"podTemplate"` Activity Activity `json:"activity"` - Services []Service `json:"services,omitempty"` + Services []Service `json:"services"` } type WorkspaceState string @@ -87,15 +87,6 @@ type ImageConfig struct { RedirectChain []RedirectStep `json:"redirectChain,omitempty"` } -type Service struct { - HttpService *HttpService `json:"httpService,omitempty"` -} - -type HttpService struct { - DisplayName string `json:"displayName"` - HttpPath string `json:"httpPath"` -} - type PodConfig struct { Current OptionInfo `json:"current"` Desired *OptionInfo `json:"desired,omitempty"` @@ -153,3 +144,12 @@ const ( ProbeResultFailure ProbeResult = "Failure" ProbeResultTimeout ProbeResult = "Timeout" ) + +type Service struct { + HttpService *HttpService `json:"httpService,omitempty"` +} + +type HttpService struct { + DisplayName string `json:"displayName"` + HttpPath string `json:"httpPath"` +}