Skip to content

Commit ecac7ac

Browse files
mathis-marcotteMathis Marcotte
andauthored
Create default notebook 2.0 (#305)
* slight refactor to reduce duplicate conditional * removed unused component * added endpoint in backend for creating default notebook * added default notebook label --------- Co-authored-by: Mathis Marcotte <[email protected]>
1 parent 6c4b579 commit ecac7ac

File tree

3 files changed

+154
-33
lines changed

3 files changed

+154
-33
lines changed

frontend/jupyter/src/app/pages/form/form-new/form-new.component.ts

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ export class FormNewComponent
2626
formCtrl: FormGroup;
2727
config: Config;
2828

29-
defaultStorageclass = false;
30-
3129
subscriptions = new Subscription();
3230

3331
readonlySpecs: boolean;
@@ -91,20 +89,6 @@ export class FormNewComponent
9189
});
9290
}),
9391
);
94-
95-
// Check if a default StorageClass is set
96-
this.backend.getDefaultStorageClass().subscribe(defaultClass => {
97-
if (defaultClass.length === 0) {
98-
this.defaultStorageclass = false;
99-
this.popup.open(
100-
$localize`No default Storage Class is set. Can't create new Disks for the new Notebook. Please use an Existing Disk.`,
101-
SnackType.Warning,
102-
0,
103-
);
104-
} else {
105-
this.defaultStorageclass = true;
106-
}
107-
});
10892
}
10993

11094
ngOnDestroy() {
@@ -133,19 +117,7 @@ export class FormNewComponent
133117
// Use the custom image instead
134118
if (notebook.customImageCheck) {
135119
notebook.image = notebook.customImage;
136-
} else if (notebook.serverType === 'group-one') {
137-
// Set notebook image from imageGroupOne
138-
notebook.image = notebook.imageGroupOne;
139-
} else if (notebook.serverType === 'group-two') {
140-
// Set notebook image from imageGroupTwo
141-
notebook.image = notebook.imageGroupTwo;
142-
} else if (notebook.serverType === 'group-three') {
143-
// Set notebook image from imageGroupThree
144-
notebook.image = notebook.imageGroupThree;
145-
}
146-
147-
// Set serverType for custom image
148-
if (notebook.customImageCheck) {
120+
// Set serverType for custom image
149121
if (notebook.image.match(/\/rstudio:/)) {
150122
notebook.serverType = 'group-one';
151123
} else if (notebook.image.match(/\/remote-desktop:/)) {
@@ -155,6 +127,15 @@ export class FormNewComponent
155127
} else {
156128
notebook.serverType = 'jupyter';
157129
}
130+
} else if (notebook.serverType === 'group-one') {
131+
// Set notebook image from imageGroupOne
132+
notebook.image = notebook.imageGroupOne;
133+
} else if (notebook.serverType === 'group-two') {
134+
// Set notebook image from imageGroupTwo
135+
notebook.image = notebook.imageGroupTwo;
136+
} else if (notebook.serverType === 'group-three') {
137+
// Set notebook image from imageGroupThree
138+
notebook.image = notebook.imageGroupThree;
158139
}
159140

160141
// Remove unnecessary images from the request sent to the backend

main.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"context"
55
"flag"
6-
"io/ioutil"
76
"log"
87
"net/http"
98
"net/url"
@@ -88,7 +87,7 @@ func main() {
8887
s := server{}
8988

9089
// Parse config
91-
cfdata, err := ioutil.ReadFile(spawnerConfigPath)
90+
cfdata, err := os.ReadFile(spawnerConfigPath)
9291
if err != nil {
9392
log.Fatal(err)
9493
}
@@ -179,6 +178,17 @@ func main() {
179178
},
180179
}, s.GetNotebooks)).Methods("GET")
181180

181+
router.HandleFunc("/api/namespaces/{namespace}/notebooks/default", s.checkAccess(authorizationv1.SubjectAccessReview{
182+
Spec: authorizationv1.SubjectAccessReviewSpec{
183+
ResourceAttributes: &authorizationv1.ResourceAttributes{
184+
Group: kubeflowv1.SchemeGroupVersion.Group,
185+
Verb: "create",
186+
Resource: "notebooks",
187+
Version: kubeflowv1.SchemeGroupVersion.Version,
188+
},
189+
},
190+
}, s.NewDefaultNotebook)).Headers("Content-Type", "application/json").Methods("POST")
191+
182192
router.HandleFunc("/api/namespaces/{namespace}/notebooks", s.checkAccess(authorizationv1.SubjectAccessReview{
183193
Spec: authorizationv1.SubjectAccessReviewSpec{
184194
ResourceAttributes: &authorizationv1.ResourceAttributes{

notebooks.go

Lines changed: 132 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ type newnotebookrequest struct {
109109
ServerType string `json:"serverType"`
110110
AffinityConfig string `json:"affinityConfig"`
111111
TolerationGroup string `json:"tolerationGroup"`
112+
DefaultNotebook bool `json:"defaultNotebook"`
112113
}
113114

114115
type gpuresponse struct {
@@ -447,6 +448,131 @@ func (s *server) handleVolume(ctx context.Context, req volrequest, notebook *kub
447448
return nil
448449
}
449450

451+
// Sets default values to notebook request if missing
452+
func (s *server) createDefaultNotebook(namespace string) (newnotebookrequest, error) {
453+
var notebook newnotebookrequest
454+
notebookname := namespace + "-notebook"
455+
cpuvalue, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.CPU.Value)
456+
if err != nil {
457+
return notebook, err
458+
}
459+
460+
cpulimitvalue, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.CPU.LimitValue)
461+
if err != nil {
462+
return notebook, err
463+
}
464+
465+
memoryvalue, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.Memory.Value + "Gi")
466+
if err != nil {
467+
return notebook, err
468+
}
469+
470+
memorylimitvalue, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.Memory.LimitValue + "Gi")
471+
if err != nil {
472+
return notebook, err
473+
}
474+
475+
size, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.WorkspaceVolume.Value.NewPvc.Spec.Resources.Requests.Storage)
476+
if err != nil {
477+
return notebook, err
478+
}
479+
workspacevolumename := notebookname + "-workspace"
480+
workspaceVol := volrequest{
481+
Mount: s.Config.SpawnerFormDefaults.WorkspaceVolume.Value.Mount,
482+
NewPvc: NewPvc{
483+
NewPvcMetadata: NewPvcMetadata{
484+
Name: &workspacevolumename,
485+
},
486+
NewPvcSpec: NewPvcSpec{
487+
Resources: Resources{
488+
Requests: Requests{
489+
Storage: size,
490+
},
491+
},
492+
AccessModes: s.Config.SpawnerFormDefaults.WorkspaceVolume.Value.NewPvc.Spec.AccessModes,
493+
StorageClassName: "",
494+
},
495+
},
496+
}
497+
498+
var datavols []volrequest
499+
for _, volreq := range s.Config.SpawnerFormDefaults.DataVolumes.Value {
500+
size, err := resource.ParseQuantity(s.Config.SpawnerFormDefaults.WorkspaceVolume.Value.NewPvc.Spec.Resources.Requests.Storage)
501+
if err != nil {
502+
return notebook, err
503+
}
504+
vol := volrequest{
505+
Mount: volreq.Value.Mount,
506+
NewPvc: NewPvc{
507+
NewPvcMetadata: NewPvcMetadata{
508+
Name: &volreq.Value.NewPvc.Metadata.Name,
509+
},
510+
NewPvcSpec: NewPvcSpec{
511+
Resources: Resources{
512+
Requests: Requests{
513+
Storage: size,
514+
},
515+
},
516+
AccessModes: workspaceVol.NewPvc.NewPvcSpec.AccessModes,
517+
StorageClassName: "",
518+
},
519+
},
520+
}
521+
datavols = append(datavols, vol)
522+
}
523+
524+
notebook = newnotebookrequest{
525+
Name: notebookname,
526+
Namespace: namespace,
527+
Image: s.Config.SpawnerFormDefaults.Image.Value,
528+
CustomImage: "",
529+
CustomImageCheck: false,
530+
CPU: cpuvalue,
531+
CPULimit: cpulimitvalue,
532+
Memory: memoryvalue,
533+
MemoryLimit: memorylimitvalue,
534+
GPUs: gpurequest{
535+
Quantity: s.Config.SpawnerFormDefaults.GPUs.Value.Num,
536+
Vendor: s.Config.SpawnerFormDefaults.GPUs.Value.Vendor,
537+
},
538+
NoWorkspace: false,
539+
Workspace: workspaceVol,
540+
DataVolumes: datavols,
541+
EnableSharedMemory: s.Config.SpawnerFormDefaults.Shm.Value,
542+
Configurations: s.Config.SpawnerFormDefaults.Configurations.Value,
543+
Protb: false,
544+
Language: "en",
545+
ImagePullPolicy: s.Config.SpawnerFormDefaults.ImagePullPolicy.Value,
546+
ServerType: "jupyter",
547+
AffinityConfig: s.Config.SpawnerFormDefaults.AffinityConfig.Value,
548+
TolerationGroup: s.Config.SpawnerFormDefaults.TolerationGroup.Value,
549+
DefaultNotebook: true,
550+
}
551+
552+
return notebook, nil
553+
}
554+
555+
func (s *server) NewDefaultNotebook(w http.ResponseWriter, r *http.Request) {
556+
vars := mux.Vars(r)
557+
namespace := vars["namespace"]
558+
559+
req, err := s.createDefaultNotebook(namespace)
560+
if err != nil {
561+
s.error(w, r, err)
562+
return
563+
}
564+
565+
newnotebook, err := json.Marshal(req)
566+
if err != nil {
567+
s.error(w, r, err)
568+
return
569+
}
570+
571+
r.Body = io.NopCloser(bytes.NewBuffer(newnotebook))
572+
573+
s.NewNotebook(w, r)
574+
}
575+
450576
func (s *server) NewNotebook(w http.ResponseWriter, r *http.Request) {
451577
vars := mux.Vars(r)
452578
namespace := vars["namespace"]
@@ -469,8 +595,7 @@ func (s *server) NewNotebook(w http.ResponseWriter, r *http.Request) {
469595
image := req.Image
470596
if req.CustomImageCheck {
471597
image = req.CustomImage
472-
}
473-
if s.Config.SpawnerFormDefaults.Image.ReadOnly {
598+
} else if s.Config.SpawnerFormDefaults.Image.ReadOnly {
474599
image = s.Config.SpawnerFormDefaults.Image.Value
475600
}
476601
image = strings.TrimSpace(image)
@@ -540,6 +665,11 @@ func (s *server) NewNotebook(w http.ResponseWriter, r *http.Request) {
540665
notebook.ObjectMeta.Labels["notebook.statcan.gc.ca/protected-b"] = "true"
541666
}
542667

668+
// AAW Customization Creating default notebook
669+
if req.DefaultNotebook {
670+
notebook.ObjectMeta.Labels["notebook.statcan.gc.ca/default-notebook"] = "true"
671+
}
672+
543673
// Add configuration items
544674
if s.Config.SpawnerFormDefaults.Configurations.ReadOnly {
545675
for _, config := range s.Config.SpawnerFormDefaults.Configurations.Value {

0 commit comments

Comments
 (0)