You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datalab.apache.org by dy...@apache.org on 2022/02/01 16:05:27 UTC

[incubator-datalab] branch develop updated: [DATALAB-2637] fixed spot instance bid checkbox

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new a45cb0a  [DATALAB-2637] fixed spot instance bid checkbox
     new 98318b2  Merge pull request #1384 from GennadiyShpak/fix/DATALAB-2637/spot-instance-checkbox
a45cb0a is described below

commit a45cb0a116baacdc3d1d4a24ae5772d444f76127
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Mon Jan 10 13:10:49 2022 +0200

    [DATALAB-2637] fixed spot instance bid checkbox
---
 ...utational-resource-create-dialog.component.html | 124 ++++++++++-----------
 ...mputational-resource-create-dialog.component.ts |  42 ++++---
 .../computational-resource-create.model.ts         |   4 +-
 3 files changed, 91 insertions(+), 79 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index 5e9095c..5599234 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -31,14 +31,14 @@
               <label class="label">Select cluster type</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
-                  <mat-select 
-                    formControlName="template_name" 
+                  <mat-select
+                    formControlName="template_name"
                     disableOptionCentering
                     panelClass="scrolling"
                     placeholder="Select cluster type"
                   >
-                    <mat-option 
-                      *ngFor="let type of clusterTypes" 
+                    <mat-option
+                      *ngFor="let type of clusterTypes"
                       [value]="type.template_name"
                       (click)="selectImage(type)"
                     >
@@ -60,12 +60,12 @@
               <div class="control">
                 <input
                   [class.danger_field]="!resourceForm?.controls['cluster_alias_name'].valid
-                        && resourceForm?.controls['cluster_alias_name'].dirty 
+                        && resourceForm?.controls['cluster_alias_name'].dirty
                         && resourceForm?.controls['cluster_alias_name'].hasError('duplication')"
-                  type="text" 
-                  class="form-control" 
+                  type="text"
+                  class="form-control"
                   placeholder="Enter cluster alias"
-                  formControlName="cluster_alias_name" 
+                  formControlName="cluster_alias_name"
                 />
                 <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('user-duplication')">
                   You have cluster with this name in current project.
@@ -73,9 +73,9 @@
                 <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('other-user-duplication')">
                   Other user has cluster with this name in current project.
                 </span>
-                <span 
-                  class="error" 
-                  *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('maxlength') 
+                <span
+                  class="error"
+                  *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('maxlength')
                     && !resourceForm?.controls['cluster_alias_name'].hasError('pattern')"
                 >
                   Cluster name cannot be longer than {{maxClusterNameLength}} characters.
@@ -93,7 +93,7 @@
                 <mat-form-field>
                   <mat-label>Select instance size</mat-label>
                   <mat-select panelClass="scrolling" formControlName="shape_master" disableOptionCentering>
-                    <mat-optgroup 
+                    <mat-optgroup
                       *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
                       [label]="item.key | underscoreless"
                     >
@@ -114,12 +114,12 @@
             <div class="control-group" *ngIf="selectedImage?.image">
               <label class="label">Total instance number</label>
               <div class="control">
-                <input 
-                  type="number" 
-                  class="form-control" 
-                  min="{{minInstanceNumber}}" 
+                <input
+                  type="number"
+                  class="form-control"
+                  min="{{minInstanceNumber}}"
                   max="{{maxInstanceNumber}}"
-                  formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)" 
+                  formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)"
                 />
                 <span class="error" *ngIf="!resourceForm?.controls.instance_number.valid">
                   <span>Only integer values greater than or equal to {{ minInstanceNumber }} and less than
@@ -153,13 +153,13 @@
                 <mat-form-field>
                   <mat-label>Select instance size</mat-label>
                   <mat-select panelClass="scrolling" formControlName="shape_slave" disableOptionCentering>
-                    <mat-optgroup 
+                    <mat-optgroup
                       *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
                       [label]="item.key | underscoreless"
                     >
-                      <mat-option 
-                        *ngFor="let list_item of item.value" 
-                        [value]="list_item.Type" 
+                      <mat-option
+                        *ngFor="let list_item of item.value"
+                        [value]="list_item.Type"
                         (click)="clearGpuType('slave')"
                       >
                         <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{
@@ -186,7 +186,7 @@
             <div class="col">
               <div class="control-group">
                 <label class="label">Master GPU type</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{ 'not-active' : !resourceForm.controls['shape_master'].value}"
                   [matTooltip]="'Please, select master instance size.'"
@@ -195,7 +195,7 @@
                   [matTooltipDisabled]="!!resourceForm.controls['shape_master'].value.length"
                 >
                   <mat-form-field>
-                    <mat-select 
+                    <mat-select
                       formControlName="master_GPU_type" disableOptionCentering
                       placeholder="Select master GPU type"
                       [disabled]="!resourceForm.controls['shape_master'].value"
@@ -215,7 +215,7 @@
               </div>
               <div class="control-group">
                 <label class="label">Master GPU сount</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{'not-active': !resourceForm.controls['master_GPU_type'].value}"
                   [matTooltip]="'Please, select master GPU type.'"
@@ -242,7 +242,7 @@
             <div class="col">
               <div class="control-group">
                 <label class="label">Slave GPU type</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{ 'not-active': !resourceForm.controls['shape_slave'].value}"
                   [matTooltip]="'Please, select slave instance size.'"
@@ -271,7 +271,7 @@
 
               <div class="control-group">
                 <label class="label">Slave GPU сount</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{'not-active': !resourceForm.controls['slave_GPU_type'].value}"
                   [matTooltip]="'Please, select slave GPU type.'"
@@ -298,7 +298,7 @@
             </div>
           </div>
         </div>
-        <div 
+        <div
           class="preemptible checkbox-group control-group"
           *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
         >
@@ -308,14 +308,14 @@
             </div>
             <span class="pl-5">Preemptible node</span>
           </div>
-          <div 
-            *ngIf="isSelected.preemptible" 
+          <div
+            *ngIf="isSelected.preemptible"
             class="preemptible-details control"
             [ngClass]="{ show: isSelected.preemptible}"
           >
-            <input 
-              type="text" 
-              class="form-control" 
+            <input
+              type="text"
+              class="form-control"
               formControlName="preemptible_instance_number"
               (keypress)="CheckUtils.isNumberKey($event)"
               (keydown.arrowup)="preemptibleCounter($event, 'increment')"
@@ -333,35 +333,35 @@
 
         <div class="checkbox-group control-group m-top-15" *ngIf="PROVIDER === 'aws'" [hidden]="!selectedImage.templates.length">
           <div class="d-flex cursor-pointer label" (click)="addAdditionalParams('spotInstances')">
-            <div class="empty-checkbox ml-10" [ngClass]="{'checked': isSelected.spotInstances}" (click)="selectSpotInstances()">
-              <span class="checked-checkbox" *ngIf="isSelected.spotInstances"></span>
+            <div class="empty-checkbox ml-10" [ngClass]="{'checked': instanceSpot}" (click)="selectSpotInstances()">
+              <span class="checked-checkbox" *ngIf="instanceSpot"></span>
             </div>
-            <span class="pl-5">Spot instance</span><span [hidden]="!isSelected.spotInstances">&nbsp;bid, %</span>
+            <span class="pl-5">Spot instance</span><span [hidden]="!instanceSpot">&nbsp;bid, %</span>
           </div>
-          <div 
-            class="control spot-details" 
-            [ngClass]="{ show: isSelected.spotInstances }"
-            *ngIf="isSelected.spotInstances"
+          <div
+            class="control spot-details"
+            [ngClass]="{ show: instanceSpot }"
+            *ngIf="instanceSpot"
           >
-            <input 
-              type="number" 
-              class="form-control" 
-              step="5" 
-              min="{{minSpotPrice}}" 
+            <input
+              type="number"
+              class="form-control"
+              step="5"
+              min="{{minSpotPrice}}"
               max="{{maxSpotPrice}}"
-              formControlName="instance_price" 
+              formControlName="instance_price"
               (keypress)="CheckUtils.isNumberKey($event)"
             />
             <span class="error error-bottom" *ngIf="!resourceForm?.controls.instance_price.valid">
               Only integer values greater than or equal to {{minSpotPrice}} and less than {{maxSpotPrice}} are allowed.
             </span>
           </div>
-          <span class="info ml-10" *ngIf="isSelected.spotInstances">When the current Spot price
+          <span class="info ml-10" *ngIf="instanceSpot">When the current Spot price
             rises above your bid price, the Spot instance is reclaimed by AWS so that it can be given to another
             customer. Make sure to backup your data on periodic basis.
           </span>
         </div>
-        <div 
+        <div
           class="checkbox-group control-group m-top-10"
           [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
           *ngIf="notebook_instance?.image !== 'docker.datalab-zeppelin'"
@@ -372,9 +372,9 @@
             </div>
             <span class="pl-5">Cluster configurations</span>
           </div>
-          <div 
-            class="config-link" 
-            *ngIf="(isSelected.configuration) 
+          <div
+            class="config-link"
+            *ngIf="(isSelected.configuration)
               && selectedImage?.image === 'docker.datalab-dataengine-service'
               && PROVIDER === 'aws'"
           >
@@ -386,14 +386,14 @@
         </div>
         <div class="checkbox-group ml-10">
           <div class="config-details" [ngClass]="{ show: isSelected.configuration }">
-            <textarea 
-              formControlName="configuration_parameters" 
+            <textarea
+              formControlName="configuration_parameters"
               placeholder="Cluster configuration template, JSON"
               data-gramm_editor="false">
             </textarea>
-            <span 
+            <span
               class="error"
-              *ngIf="!resourceForm?.controls.configuration_parameters.valid 
+              *ngIf="!resourceForm?.controls.configuration_parameters.valid
                 && resourceForm?.controls['configuration_parameters'].dirty"
             >
               Configuration parameters is not in a valid format.
@@ -410,21 +410,21 @@
           </small>
         </div>
         <div class="text-center m-top-30">
-          <button 
-            mat-raised-button 
-            type="button" 
-            (click)="dialogRef.close()" 
+          <button
+            mat-raised-button
+            type="button"
+            (click)="dialogRef.close()"
             class="butt action"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button 
-            type="button" 
+          <button
+            mat-raised-button
+            type="button"
             [disabled]="!resourceForm?.valid 
               || (!resourceForm.value.shape_slave) 
               || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version)"
-            (click)="createComputationalResource(resourceForm.value)" 
+            (click)="createComputationalResource(resourceForm.value)"
             class="butt butt-success action"
             [ngClass]="{'not-allowed': !resourceForm?.valid 
               || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.shape_slave) 
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 6fd9991..9b03fdf 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
@@ -18,7 +18,7 @@
  */
 
 import { Component, OnInit, Inject, ChangeDetectorRef } from '@angular/core';
-import {FormGroup, FormBuilder, Validators} from '@angular/forms';
+import {FormGroup, FormBuilder, Validators, FormControl, ValidatorFn} from '@angular/forms';
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
@@ -97,12 +97,15 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   }
 
   public selectSpotInstances(): void {
-    if (this.isSelected.spotInstances) {
+    if (!this.instanceSpot) {
       this.spotInstance = true;
-      this.resourceForm.controls['instance_price'].setValue(50);
+      this.resourceForm.controls['emr_slave_instance_spot'].patchValue(true);
+      this.resourceForm.controls['instance_price'].enable();
+      this.resourceForm.controls['instance_price'].patchValue(50);
     } else {
       this.spotInstance = false;
-      this.resourceForm.controls['instance_price'].setValue(0);
+      this.resourceForm.controls['emr_slave_instance_spot'].patchValue(false);
+      this.resourceForm.controls['instance_price'].disable();
     }
   }
 
@@ -141,11 +144,11 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
 
   public createComputationalResource(data) {
     this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance,
-      this.spotInstance, this.PROVIDER.toLowerCase(), this.isSelected.gpu)
+      this.PROVIDER.toLowerCase(), this.isSelected.gpu)
       .subscribe(
         (response: any) => {
           if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close(true);
-        }, 
+        },
         error => this.toastr.error(error.message, 'Oops!')
       );
   }
@@ -155,6 +158,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       template_name: ['', [Validators.required]],
       version: [''],
       shape_master: ['', Validators.required],
+      emr_slave_instance_spot: '',
       shape_slave: [''],
       cluster_alias_name: ['', [
         Validators.required, Validators.pattern(PATTERNS.namePattern),
@@ -165,7 +169,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       preemptible_instance_number: [0,
         Validators.compose([Validators.pattern(PATTERNS.integerRegex),
         this.validPreemptibleRange.bind(this)])],
-      instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
+      instance_price: [0, [this.validInstanceSpotRange()]],
       configuration_parameters: ['', [this.validConfiguration.bind(this)]],
       custom_tag: [this.notebook_instance.tags.custom_tag],
       master_GPU_type: [''],
@@ -196,7 +200,8 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
         this.maxSpotPrice = this.selectedImage.limits.max_emr_spot_instance_bid_pct;
 
         this.isSelected.spotInstances = true;
-        this.selectSpotInstances();
+        this.resourceForm.controls['emr_slave_instance_spot'].setValue(true);
+        this.resourceForm.controls['instance_price'].setValue(50);
       }
 
       this.resourceForm.controls['instance_number'].setValue(this.minInstanceNumber);
@@ -239,17 +244,20 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     }
   }
 
-  private validInstanceSpotRange(control) {
-    if (this.isSelected.spotInstances) {
-      return this.isSelected.spotInstances
-        ? (control.value >= this.minSpotPrice && control.value <= this.maxSpotPrice ? null : { valid: false })
-        : control.value;
-    }
+  private validInstanceSpotRange(): ValidatorFn {
+    return (control: FormControl) => {
+      if (!this.isSelected.spotInstances) {
+        return null;
+      }
+      return control.value >= this.minSpotPrice && control.value <= this.maxSpotPrice
+        ? null
+        : { valid: false };
+    };
   }
 
   private validConfiguration(control) {
     if (this.isSelected.configuration) {
-      return this.isSelected.configuration 
+      return this.isSelected.configuration
         ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
         : null;
     }
@@ -373,4 +381,8 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       this.resourceForm.controls['slave_GPU_count'].setValue('');
     }
   }
+
+  get instanceSpot() {
+    return this.resourceForm.controls['emr_slave_instance_spot'].value;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
index 596f8ea..59b1d36 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
@@ -28,7 +28,7 @@ export class ComputationalResourceModel {
 
   constructor(private userResourceService: UserResourceService) { }
 
-  public createComputationalResource(parameters, image, env, spot, provider, gpu?): Observable<{}> {
+  public createComputationalResource(parameters, image, env, provider, gpu?): Observable<{}> {
     const config = parameters.configuration_parameters ? JSON.parse(parameters.configuration_parameters) : null;
 
     if (provider === 'aws' && image.image === 'docker.datalab-dataengine-service') {
@@ -41,7 +41,7 @@ export class ComputationalResourceModel {
         notebook_name: env.name,
         image: image.image,
         template_name: image.template_name,
-        emr_slave_instance_spot: spot,
+        emr_slave_instance_spot: parameters.emr_slave_instance_spot,
         emr_slave_instance_spot_pct_price: parameters.instance_price,
         config: config,
         project: env.project,

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