You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datalab.apache.org by dg...@apache.org on 2021/02/02 14:44:40 UTC

[incubator-datalab] 01/05: [DATALAB-2233]: Add possibility to create jupiter with GPU

This is an automated email from the ASF dual-hosted git repository.

dgnatyshyn pushed a commit to branch DATALAB-2246
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git

commit 47ef2bebb27ff756cb781cdb90849efa37f86f82
Author: Dmytro_Gnatyshyn <di...@ukr.net>
AuthorDate: Mon Feb 1 14:33:16 2021 +0200

    [DATALAB-2233]: Add possibility to create jupiter with GPU
---
 .../webapp/src/app/core/util/helpUtils.ts          | 20 ++++++
 ...mputational-resource-create-dialog.component.ts | 26 +------
 .../create-environment.component.html              | 82 +++++++++++++++++++---
 .../create-environment.component.scss              |  5 ++
 .../create-environment.component.ts                | 75 +++++++++++++++++---
 5 files changed, 167 insertions(+), 41 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
index 68178d5..edd51c9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
@@ -35,4 +35,24 @@ export class HelpUtils {
         return;
     }
   }
+
+  public static setGPUCount(type, gpuType): Array<number> {
+    let count = [];
+    switch (type) {
+      case 'n1-highmem-32' || 'n1-highcpu-32':
+        count = [4, 8];
+        break;
+      case 'n1-highmem-16':
+        count = [2, 4, 8];
+        break;
+      default:
+        count = [1, 2, 4, 8];
+        break;
+    }
+    if (gpuType === 'nvidia-tesla-t4') {
+      count.pop();
+    }
+
+    return count;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index 4822dc0..9411daa 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -24,7 +24,7 @@ import { ToastrService } from 'ngx-toastr';
 
 import { ComputationalResourceModel } from './computational-resource-create.model';
 import { UserResourceService } from '../../../core/services';
-import { HTTP_STATUS_CODES, PATTERNS, CheckUtils, SortUtils } from '../../../core/util';
+import {HTTP_STATUS_CODES, PATTERNS, CheckUtils, SortUtils, HelpUtils} from '../../../core/util';
 
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from './cluster-configuration-templates';
@@ -350,33 +350,13 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     }
   }
 
-  public setGPUCount(type, gpuType): Array<number> {
-    let count = [];
-    switch (type) {
-      case 'n1-highmem-32' || 'n1-highcpu-32':
-        count = [4, 8];
-        break;
-      case 'n1-highmem-16':
-        count = [2, 4, 8];
-        break;
-      default:
-        count = [1, 2, 4, 8];
-        break;
-    }
-    if (gpuType === 'nvidia-tesla-t4') {
-      count.pop();
-    }
-
-    return count;
-  }
-
   public setCount(type: any, gpuType: any): void {
     if (type === 'master') {
       const masterShape = this.resourceForm.controls['shape_master'].value;
-      this.masterGPUcount = this.setGPUCount(masterShape, gpuType);
+      this.masterGPUcount = HelpUtils.setGPUCount(masterShape, gpuType);
     } else {
       const slaveShape = this.resourceForm.controls['shape_slave'].value;
-      this.slaveGPUcount = this.setGPUCount(slaveShape, gpuType);
+      this.slaveGPUcount = HelpUtils.setGPUCount(slaveShape, gpuType);
     }
   }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
index eabff73..9cd1c8c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
@@ -164,18 +164,84 @@
         <div *ngIf="currentTemplate">
           <div class="checkbox-group"
                *ngIf="currentTemplate?.image !== 'docker.datalab-zeppelin' && currentTemplate?.image !== 'docker.datalab-superset' && currentTemplate?.image !== 'docker.datalab-jupyterlab'">
-              <label>
-                  <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Spark configurations
-              </label>
-              <div class="config-details" [ngClass]="{ show: configuration?.nativeElement['checked'] || false }">
+<!--            <label>-->
+<!--              <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Spark configurations-->
+<!--            </label>-->
+            <div class="d-flex cursor-pointer label m-bott-20" (click)="selectConfiguration()">
+              <div class="empty-checkbox" [ngClass]="{'checked': this.additionalParams.configurationNode}">
+                <span class="checked-checkbox" *ngIf="this.additionalParams.configurationNode"></span>
+              </div>
+              <span class=" pl-5">Spark configurations</span>
+            </div>
+            <div class="config-details" [ngClass]="{ show: this.additionalParams.configurationNode}">
               <textarea formControlName="cluster_config" placeholder="Cluster configuration template, JSON"
                         data-gramm_editor="false" id="config"></textarea>
-                  <span class="error spark-config"
-                        *ngIf="!createExploratoryForm?.controls.cluster_config.valid && createExploratoryForm?.controls['cluster_config'].dirty">Configuration
+              <span class="error spark-config"
+                    *ngIf="!createExploratoryForm?.controls.cluster_config.valid && createExploratoryForm?.controls['cluster_config'].dirty">Configuration
                 parameters is not in a valid format.</span>
-              </div>
+            </div>
           </div>
+          <ng-template [ngIf]="selectedCloud === 'gcp'">
+            <div class="checkbox-group">
+              <div class="d-flex cursor-pointer label m-bott-20" (click)="addGpuFields()">
+                <div class="empty-checkbox" [ngClass]="{'checked': this.additionalParams.gpu}">
+                  <span class="checked-checkbox" *ngIf="this.additionalParams.gpu"></span>
+                </div>
+                <span class=" pl-5">GPU</span>
+              </div>
+              <ng-template [ngIf]="this.additionalParams.gpu">
+                <div class="control-group">
+                  <label class="label">Master GPU type</label>
+                  <div class="control selector-wrapper"
+                       [matTooltip]="'Please, select instance size.'"
+                       matTooltipPosition="above"
+                       [matTooltipClass]="'full-size-tooltip'"
+                       [matTooltipDisabled]="!!createExploratoryForm.controls['shape'].value"
+                  >
+                <span class="form-field-wrapper" [ngClass]="{ 'not-active': !createExploratoryForm.controls['shape'].value}">
+                <mat-form-field>
+                  <mat-label>Select master GPU type</mat-label>
+                  <mat-select formControlName="master_GPU_type" disableOptionCentering [disabled]="!createExploratoryForm.controls['shape'].value"
+                              panelClass="create-resources-shapes" placeholder="Master GPU type">
+                      <mat-option *ngFor="let list_item of masterGPUtype" [value]="list_item.Gpu_type" (click)="setCount('', list_item.Gpu_type)">
+                        <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Gpu_type }}
+                      </mat-option>
 
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+                </span>
+                  </div>
+                </div>
+                <div class="control-group">
+                  <label class="label">Master GPU count</label>
+                  <div class="control selector-wrapper"
+                       [matTooltip]="'Please, select master GPU type.'"
+                       matTooltipPosition="above"
+                       [matTooltipClass]="'full-size-tooltip'"
+                       [matTooltipDisabled]="!!createExploratoryForm.controls['master_GPU_type'].value"
+                  >
+                <span class="form-field-wrapper" [ngClass]="{ 'not-active': !createExploratoryForm.controls['master_GPU_type'].value}">
+                <mat-form-field>
+                  <mat-label>Select master GPU count</mat-label>
+                  <mat-select formControlName="master_GPU_count" disableOptionCentering [disabled]="!createExploratoryForm.controls['master_GPU_type'].value"
+                              panelClass="create-resources-shapes" placeholder="Master GPU count">
+                      <mat-option *ngFor="let list_item of masterGPUcount" [value]="list_item">
+                        {{ list_item }}
+                      </mat-option>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+                </span>
+                  </div>
+                </div>
+              </ng-template>
+          </div>
+          </ng-template>
             <small *ngIf="currentTemplate?.image === 'docker.datalab-zeppelin'">
                 Spark default configuration for Apache Zeppelin can not be changed from DataLab UI. Currently it can be
                 done directly through Apache Zeppelin interpreter menu.
@@ -185,7 +251,7 @@
             </small>
         </div>
 
-        <div class="text-center m-top-30">
+        <div class="text-center m-top-30"  id="buttons">
           <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Cancel</button>
           <button mat-raised-button type="button" class="butt butt-success action"
             [disabled]="!createExploratoryForm?.valid"
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
index aecad81..6baf727 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
@@ -18,6 +18,11 @@
  */
 
 .checkbox-group {
+
+  .empty-checkbox{
+    margin: 0;
+  }
+
   .config-details {
     height: 0;
     opacity: 0;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
index f7cb25a..1c50761 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
@@ -24,10 +24,11 @@ import { ToastrService } from 'ngx-toastr';
 
 import { Project } from '../../../administration/project/project.component';
 import { UserResourceService, ProjectService } from '../../../core/services';
-import { CheckUtils, SortUtils, HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
+import {CheckUtils, SortUtils, HTTP_STATUS_CODES, PATTERNS, HelpUtils} from '../../../core/util';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from '../../computational/computational-resource-create-dialog/cluster-configuration-templates';
 import {tap} from 'rxjs/operators';
+import {timer} from 'rxjs';
 
 @Component({
   selector: 'create-environment',
@@ -49,8 +50,19 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
   images: Array<any>;
   maxNotebookLength: number = 14;
   public areShapes: boolean;
+  public selectedCloud: string = '';
+  public masterGPUcount: Array<number>;
+  public masterGPUtype = [
+    {Size: 'S', Gpu_type: 'nvidia-tesla-t4'},
+    {Size: 'M', Gpu_type: 'nvidia-tesla-v100'}
+  ];
+
+  public additionalParams = {
+    configurationNode: false,
+    gpu: false,
+  };
+
 
-  @ViewChild('configurationNode') configuration;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) public data: any,
@@ -91,13 +103,18 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
 
   public setEndpoints(project) {
     if (this.images) this.images = [];
-
+    if (this.selectedCloud) this.selectedCloud = '';
     this.endpoints = project.endpoints
       .filter(e => e.status === 'RUNNING')
       .map(e => e.name);
+
   }
 
   public getTemplates(project, endpoint) {
+    if (this.selectedCloud) this.selectedCloud = '';
+    const endpoints = this.data.environments.find(env => env.project === project).endpoints;
+    this.selectedCloud = endpoints.find(endp => endp.name === endpoint).cloudProvider.toLowerCase();
+
     this.userResourceService.getExploratoryTemplates(project, endpoint)
       .pipe(tap(results => {
 
@@ -153,11 +170,47 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
   }
 
   public selectConfiguration() {
-    const value = (this.configuration.nativeElement.checked && this.createExploratoryForm)
-      ? JSON.stringify(CLUSTER_CONFIGURATION.SPARK, undefined, 2) : '';
+    this.additionalParams.configurationNode = !this.additionalParams.configurationNode;
+    if (this.additionalParams.configurationNode) {
+      const value = (this.additionalParams.configurationNode && this.createExploratoryForm)
+        ? JSON.stringify(CLUSTER_CONFIGURATION.SPARK, undefined, 2) : '';
+      timer(500).subscribe(_ => {
+        document.querySelector('#buttons').scrollIntoView({ block: 'start', behavior: 'smooth' });
+      });
+      this.createExploratoryForm.controls['cluster_config'].setValue(value);
+    }
+  }
+
+  public addGpuFields() {
+    this.additionalParams.gpu = !this.additionalParams.gpu;
+
+    const controls = ['master_GPU_type', 'master_GPU_count'];
+    if (!this.additionalParams.gpu) {
+      controls.forEach(control => {
+        this.createExploratoryForm.controls[control].setValue(null);
+        this.createExploratoryForm.controls[control].clearValidators();
+        this.createExploratoryForm.controls[control].updateValueAndValidity();
+      });
+
+    } else {
+      controls.forEach(control => {
+        this.createExploratoryForm.controls[control].setValidators([Validators.required]);
+        this.createExploratoryForm.controls[control].updateValueAndValidity();
+      });
+      timer(100).subscribe(_ => {
+        document.querySelector('#buttons').scrollIntoView({ block: 'start', behavior: 'smooth' });
+      });
+    }
+  }
 
-    document.querySelector('#config').scrollIntoView({ block: 'start', behavior: 'smooth' });
-    this.createExploratoryForm.controls['cluster_config'].setValue(value);
+  public setCount(type: any, gpuType: any): void {
+    // if (type === 'master') {
+      const masterShape = this.createExploratoryForm.controls['shape'].value;
+      this.masterGPUcount = HelpUtils.setGPUCount(masterShape, gpuType);
+    // } else {
+    //   const slaveShape = this.resourceForm.controls['shape_slave'].value;
+    //   this.slaveGPUcount = HelpUtils.setGPUCount(slaveShape, gpuType);
+    // }
   }
 
   private initFormModel(): void {
@@ -174,7 +227,9 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
         this.checkDuplication.bind(this)
       ]],
       cluster_config: ['', [this.validConfiguration.bind(this)]],
-      custom_tag: ['', [Validators.pattern(PATTERNS.namePattern)]]
+      custom_tag: ['', [Validators.pattern(PATTERNS.namePattern)]],
+      master_GPU_type: [null],
+      master_GPU_count: [null],
     });
   }
 
@@ -193,8 +248,8 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
   }
 
   private validConfiguration(control) {
-    if (this.configuration)
-      return this.configuration.nativeElement['checked']
+    if (this.additionalParams.configurationNode)
+      return this.additionalParams.configurationNode
         ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
         : null;
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org