Skip to content

Commit

Permalink
Feature: Pool rescale supports autoscale (#325)
Browse files Browse the repository at this point in the history
* Pool rescale support forumla

* Pool resize fixes

* Fixes
  • Loading branch information
timotheeguerin authored Apr 17, 2017
1 parent 19facf8 commit 26c5da3
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 35 deletions.
58 changes: 46 additions & 12 deletions app/components/pool/action/resize/pool-resize-dialog.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Component, Input } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { FormBuilder, FormControl } from "@angular/forms";
import { autobind } from "core-decorators";
import * as moment from "moment";
import { Observable } from "rxjs";

import { NotificationService } from "app/components/base/notifications";
import { SidebarRef } from "app/components/base/sidebar";
import { Pool } from "app/models";
import { PoolEnableAutoScaleDto } from "app/models/dtos";
import { PoolScaleModel } from "app/models/forms";
import { PoolService } from "app/services";
import { CustomValidators } from "app/utils";

@Component({
selector: "bl-pool-resize-dialog",
Expand All @@ -17,13 +20,17 @@ export class PoolResizeDialogComponent {
public set pool(pool: Pool) {
if (pool) {
this._pool = pool;
this.form.patchValue({
const interval = pool.autoScaleEvaluationInterval ? pool.autoScaleEvaluationInterval.asMinutes() : 15;
this.scale.patchValue(<PoolScaleModel>{
targetDedicated: pool.targetDedicated,
enableAutoScale: pool.enableAutoScale,
autoScaleFormula: pool.autoScaleFormula,
autoScaleEvaluationInterval: interval,
});
}
}
public get pool() { return this._pool; }
public form: FormGroup;
public scale: FormControl;

private _pool: Pool;

Expand All @@ -32,24 +39,51 @@ export class PoolResizeDialogComponent {
public sidebarRef: SidebarRef<PoolResizeDialogComponent>,
private notificationService: NotificationService,
private poolService: PoolService) {
this.form = this.formBuilder.group({
targetDedicated: [0, [Validators.required, CustomValidators.number, CustomValidators.min(0)]],
this.scale = this.formBuilder.control({
scale: [null],
});
}

@autobind()
public submit() {
const id = this.pool.id;
const targetDedicated = this.form.value.targetDedicated;
const obs = this.poolService.resize(id, targetDedicated, {});
const value: PoolScaleModel = this.scale.value;
let obs;
if (value.enableAutoScale) {
obs = this._enableAutoScale(value);
} else {
const targetDedicated = value.targetDedicated;
obs = this._disableAutoScale().flatMap(() => this.poolService.resize(id, targetDedicated));
}

obs.subscribe({
complete: () => {
const finalObs = obs.flatMap(() => this.poolService.getOnce(this.pool.id)).share();
finalObs.subscribe({
next: (pool) => {
this.notificationService.success("Pool resize started!",
`Pool '${id}' will resize to ${targetDedicated} nodes!`);
`Pool '${id}' will resize to ${pool.targetDedicated} nodes!`);
},
error: () => null,
});
return obs;
return finalObs;
}

private _enableAutoScale(value: PoolScaleModel) {
if (this.pool.enableAutoScale) {
return Observable.of({});
} else {
const dto = new PoolEnableAutoScaleDto({
autoScaleFormula: value.autoScaleFormula,
autoScaleEvaluationInterval: moment.duration(value.autoScaleEvaluationInterval, "minutes") as any,
});
return this.poolService.enableAutoScale(this.pool.id, dto);
}
}

private _disableAutoScale() {
if (this.pool.enableAutoScale) {
return this.poolService.disableAutoScale(this.pool.id).delay(1000);
} else {
return Observable.of({});
}
}
}
10 changes: 3 additions & 7 deletions app/components/pool/action/resize/pool-resize-dialog.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
<div class="slideout-form content-wrapper">
<h1>Resize your pool</h1>
<p>You can manually resize the number of nodes in the pool</p>
<bl-action-form [submit]="submit" [sidebarRef]="sidebarRef" [formGroup]="form">
<form *ngIf="pool" [formGroup]="form">
<div class="form-element">
<md-input-container>
<input mdInput type="number" placeholder="Target Dedicated" formControlName="targetDedicated" min="0">
</md-input-container>
</div>
<bl-action-form [submit]="submit" [sidebarRef]="sidebarRef" [formGroup]="scale">
<form *ngIf="pool">
<bl-pool-scale-picker [formControl]="scale"> </bl-pool-scale-picker>
</form>
</bl-action-form>
</div>
10 changes: 9 additions & 1 deletion app/components/pool/action/scale/pool-scale-picker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Subscription } from "rxjs";
export class PoolScalePickerComponent implements OnDestroy, ControlValueAccessor {
public form: FormGroup;

public selectedModeTab = 0;

private _propagateChange: Function;
private _sub: Subscription;

Expand All @@ -39,7 +41,11 @@ export class PoolScalePickerComponent implements OnDestroy, ControlValueAccessor
}

public writeValue(value: any) {
this.form.patchValue(value || {});
value = value || {};
this.form.patchValue(value);
if (value.enableAutoScale) {
this.selectedModeTab = 1;
}
}

public registerOnChange(fn) {
Expand All @@ -62,6 +68,8 @@ export class PoolScalePickerComponent implements OnDestroy, ControlValueAccessor
}

public changeScaleModeTab(event) {
this.selectedModeTab = event.index;

if (event.index === 0) {
this.form.patchValue({ enableAutoScale: false });
} else if (event.index === 1) {
Expand Down
2 changes: 1 addition & 1 deletion app/components/pool/action/scale/pool-scale-picker.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div [formGroup]="form">
<md-tab-group class="form-tabs" (selectChange)="changeScaleModeTab($event)">
<md-tab-group class="form-tabs" [selectedIndex]="selectedModeTab" (selectChange)="changeScaleModeTab($event)">
<md-tab label="Fixed">
<md-input-container>
<input mdInput formControlName="targetDedicated" placeholder="Number of virtual machines in pool" type="number" />
Expand Down
5 changes: 0 additions & 5 deletions app/components/pool/details/pool-details.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { MdDialog, MdDialogConfig } from "@angular/material";
import { ActivatedRoute, Router } from "@angular/router";
import { autobind } from "core-decorators";
import { List } from "immutable";
import * as Moment from "moment";
import { Subscription } from "rxjs";

import { JobCreateBasicDialogComponent } from "app/components/job/action";
Expand Down Expand Up @@ -117,10 +116,6 @@ export class PoolDetailsComponent implements OnInit, OnDestroy {
}
}

public get lastResize(): string {
return Moment(this.pool.allocationStateTransitionTime).fromNow();
}

@autobind()
public updateTags(newTags: List<string>) {
return this.poolService.updateTags(this.pool, newTags).flatMap(() => {
Expand Down
2 changes: 1 addition & 1 deletion app/components/pool/details/pool-details.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</div>
</md-card-title-group>
<md-card-content>
<p>Last resized {{lastResize}}</p>
<p>Last resized {{poolDecorator.lastResized}}</p>
<p><i class="fa fa-{{poolDecorator.poolOsIcon}}" aria-hidden="true"></i> {{poolDecorator.poolOs}}</p>
<bl-tags [tags]="pool.tags" [editable]="true" [save]="updateTags" noTagsMessage="No tags."></bl-tags>
</md-card-content>
Expand Down
4 changes: 4 additions & 0 deletions app/models/decorators/pool-decorator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Pool } from "app/models";
import { DecoratorBase } from "app/utils/decorators";
import * as moment from "moment";
import { CloudServiceConfigurationDecorator } from "./cloud-service-configuration-decorator";
import { TaskSchedulingPolicyDecorator } from "./task-scheduling-policy-decorator";
import { VirtualMachineConfigurationDecorator } from "./virtual-machine-configuration-decorator";
Expand Down Expand Up @@ -31,6 +32,7 @@ export class PoolDecorator extends DecoratorBase<Pool> {
public vmSize: string;
public poolOs: string;
public poolOsIcon: string;
public lastResized: string;

constructor(private pool?: Pool) {
super(pool);
Expand Down Expand Up @@ -62,6 +64,8 @@ export class PoolDecorator extends DecoratorBase<Pool> {

this.poolOs = this._computePoolOs();
this.poolOsIcon = this._computePoolOsIcon(this.poolOs);

this.lastResized = moment(this.pool.allocationStateTransitionTime).fromNow();
}

private _computePoolOs(): string {
Expand Down
1 change: 1 addition & 0 deletions app/models/dtos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* This folder is used for interfaces used for creating/updating entities
*/
export * from "./pool-create.dto";
export * from "./pool-enable-autoscale.dto";
export * from "./job-create.dto";
export * from "./task-create.dto";
export * from "./metadata.dto";
9 changes: 9 additions & 0 deletions app/models/dtos/pool-enable-autoscale.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Dto, DtoAttr } from "app/core";

export class PoolEnableAutoScaleDto extends Dto<PoolEnableAutoScaleDto> {
@DtoAttr()
public autoScaleFormula?: string;

@DtoAttr()
public autoScaleEvaluationInterval?: moment.Duration;
}
23 changes: 15 additions & 8 deletions app/services/pool-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable } from "@angular/core";
import { Observable, Subject } from "rxjs";

import { Pool } from "app/models";
import { PoolCreateDto } from "app/models/dtos";
import { PoolCreateDto, PoolEnableAutoScaleDto } from "app/models/dtos";
import { ModelUtils, log } from "app/utils";
import { List } from "immutable";
import { BatchClientService } from "./batch-client.service";
Expand Down Expand Up @@ -80,14 +80,9 @@ export class PoolService extends ServiceBase {
}

public resize(poolId: string, targetDedicated: number, options: any = {}) {
let observable = this.callBatchClient((client) => client.pool.resize(poolId, targetDedicated, options));
observable.subscribe({
error: (error) => {
log.error("Error resizing pool: " + poolId, Object.assign({}, error));
},
return this.callBatchClient((client) => client.pool.resize(poolId, targetDedicated, options), (error) => {
log.error("Error resizing pool: " + poolId, Object.assign({}, error));
});

return observable;
}

public patch(poolId: string, attributes: any, options: any = {}) {
Expand All @@ -108,4 +103,16 @@ export class PoolService extends ServiceBase {
};
return this.patch(pool.id, attributes);
}

public enableAutoScale(poolId: string, autoscaleParams: PoolEnableAutoScaleDto) {
return this.callBatchClient((client) => client.pool.enableAutoScale(poolId, autoscaleParams), (error) => {
log.error("Error enabling autoscale for pool: " + poolId, error);
});
}

public disableAutoScale(poolId: string) {
return this.callBatchClient((client) => client.pool.disableAutoScale(poolId), (error) => {
log.error("Error disabling autoscale for pool: " + poolId, error);
});
}
}
13 changes: 13 additions & 0 deletions client/api/batch-client-proxy/poolProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,17 @@ export default class PoolProxy {
pool = ProxyUtil.decoratePool(pool);
return this.client.pool.add(pool, wrapOptions(options));
}

public enableAutoScale(
poolId: string,
attributes: models.PoolEnableAutoScaleParameter,
options?: any): Promise<any> {
attributes = ProxyUtil.decoratePool(attributes);

return this.client.pool.enableAutoScale(poolId, attributes, wrapOptions(options));
}

public disableAutoScale(poolId: string, options?: any): Promise<any> {
return this.client.pool.disableAutoScale(poolId, wrapOptions(options));
}
}

0 comments on commit 26c5da3

Please sign in to comment.