From 4e4eb6cb018ab5d82e499b0138d0fa9a9ae701e9 Mon Sep 17 00:00:00 2001 From: Shiran Pasternak Date: Fri, 1 Apr 2022 14:04:50 -0400 Subject: [PATCH] Unrevert "Update to call List Supported Virtual Machine and Cloud Service SKUs (#2400)" 8a7424bb84974e90752e4a480a677c31cdcbc9ed Batch Service supports VM SKU API so reenabling service call. --- .../toggle-filter-button.component.spec.ts | 2 +- ...gallery-application-list.component.spec.ts | 2 +- .../services/compute/vm-size.service.spec.ts | 128 +++----- src/app/services/compute/vm-size.service.ts | 297 +++++++++++++----- .../compute/vmsize_sample_responses.ts | 71 ++--- 5 files changed, 293 insertions(+), 207 deletions(-) diff --git a/src/@batch-flask/ui/browse-layout/toggle-filter-button/toggle-filter-button.component.spec.ts b/src/@batch-flask/ui/browse-layout/toggle-filter-button/toggle-filter-button.component.spec.ts index a77adc26f2..cbd211f14b 100644 --- a/src/@batch-flask/ui/browse-layout/toggle-filter-button/toggle-filter-button.component.spec.ts +++ b/src/@batch-flask/ui/browse-layout/toggle-filter-button/toggle-filter-button.component.spec.ts @@ -48,7 +48,7 @@ describe("ToggleFilterButtonComponent", () => { }); }); - describe("when fitler is empty", () => { + describe("when filter is empty", () => { it("should not show marker", () => { expect(de.query(By.css(".filtering"))).toBeFalsy(); }); diff --git a/src/app/components/gallery/application-list/gallery-application-list.component.spec.ts b/src/app/components/gallery/application-list/gallery-application-list.component.spec.ts index f42281d90d..2f229fc42f 100644 --- a/src/app/components/gallery/application-list/gallery-application-list.component.spec.ts +++ b/src/app/components/gallery/application-list/gallery-application-list.component.spec.ts @@ -88,7 +88,7 @@ describe("GalleryApplicationList", () => { expect(apps[3].query(By.css(".logo")).nativeElement.getAttribute("src")).toEqual(applications[2].icon); }); - it("fitler", () => { + it("filter", () => { testComponent.filter = "m"; fixture.detectChanges(); diff --git a/src/app/services/compute/vm-size.service.spec.ts b/src/app/services/compute/vm-size.service.spec.ts index 5e8a5f617e..98cc779989 100644 --- a/src/app/services/compute/vm-size.service.spec.ts +++ b/src/app/services/compute/vm-size.service.spec.ts @@ -3,9 +3,10 @@ import { BehaviorSubject, of } from "rxjs"; import { take } from "rxjs/operators"; import { VmSizeService } from "./vm-size.service"; import { - vmSizeSampleResponse as vmSizesResponse, badResponseIsNaN, - responseWithExtraCapability + responseWithExtraCapability, + virtualMachineResponse, + cloudServiceResponse } from "./vmsize_sample_responses"; const sub1 = new ArmSubscription({ @@ -13,31 +14,9 @@ const sub1 = new ArmSubscription({ subscriptionId: "sub1", }); -const githubDataResponse = { - category: { - all: [".*"], - memory: [ - "^standard_d[0-9a-z]*$", - ], - }, - all: [ - "^standard_d[0-9]*$", - ], - paas: [ - "small", - "medium", - "large", - "extralarge", - ], - iaas: [ - "^standard_a[1-9][0-9]*$", - ], -}; - describe("VMSizeService", () => { let service: VmSizeService; let armSpy; - let githubDataSpy; let accountServiceSpy; const testWestusAccount = new ArmBatchAccount({ @@ -48,19 +27,34 @@ describe("VMSizeService", () => { subscription: sub1, }); + const testBrazilAccount = new ArmBatchAccount({ + id: "/subs/sub-1/batchaccounts/acc-2", + name: "acc-2", + location: "brazilsouth", + properties: {} as any, + subscription: sub1, + }); + + // westus account + const westusCloudServiceQuery = `/subscriptions/${testWestusAccount.subscription.subscriptionId}/providers/Microsoft.Batch/locations/${testWestusAccount.location}/cloudServiceSkus?api-version=2021-06-01`; + const westusVMQuery = `/subscriptions/${testWestusAccount.subscription.subscriptionId}/providers/Microsoft.Batch/locations/${testWestusAccount.location}/virtualMachineSkus?api-version=2021-06-01`; + // brazilsouth account + const brazilCloudServiceQuery = `/subscriptions/${testBrazilAccount.subscription.subscriptionId}/providers/Microsoft.Batch/locations/${testBrazilAccount.location}/cloudServiceSkus?api-version=2021-06-01` + const brazilVMQuery = `/subscriptions/${testBrazilAccount.subscription.subscriptionId}/providers/Microsoft.Batch/locations/${testBrazilAccount.location}/virtualMachineSkus?api-version=2021-06-01` + beforeEach(() => { armSpy = { - get: jasmine.createSpy("arm.get").and.returnValue(of(vmSizesResponse)), - }; - - githubDataSpy = { - get: jasmine.createSpy("githubData.get").and.returnValue(of(JSON.stringify(githubDataResponse))), + get: jasmine.createSpy("arm.get") + .withArgs(westusVMQuery).and.returnValue(of(virtualMachineResponse)) + .withArgs(westusCloudServiceQuery).and.returnValue(of(cloudServiceResponse)) + .withArgs(brazilCloudServiceQuery).and.returnValue(of(cloudServiceResponse)) + .withArgs(brazilVMQuery).and.returnValue(of(virtualMachineResponse)) }; accountServiceSpy = { currentAccount: new BehaviorSubject(testWestusAccount), }; - service = new VmSizeService(armSpy, githubDataSpy, accountServiceSpy); + service = new VmSizeService(armSpy, accountServiceSpy); }); afterEach(() => { @@ -68,49 +62,31 @@ describe("VMSizeService", () => { }); it("use the batch account subscription and location for the sizes", async () => { + expect(armSpy.get).toHaveBeenCalledTimes(0); await service.sizes.pipe(take(1)).toPromise(); - expect(armSpy.get).toHaveBeenCalledOnce(); - - const expectedOptionsParam = { - params: { - "$filter": `location eq '${testWestusAccount.location}'` - } - }; - - expect(armSpy.get).toHaveBeenCalledWith( - "subscriptions/sub1/providers/Microsoft.Compute/skus", expectedOptionsParam); + expect(armSpy.get).toHaveBeenCalledWith(westusVMQuery); + expect(armSpy.get).toHaveBeenCalledWith(westusCloudServiceQuery); }); it("only calls the vm sizes api once per account", async () => { await service.sizes.pipe(take(1)).toPromise(); - expect(armSpy.get).toHaveBeenCalledOnce(); + expect(armSpy.get).toHaveBeenCalledTimes(2); await service.sizes.pipe(take(1)).toPromise(); - expect(armSpy.get).toHaveBeenCalledOnce(); + expect(armSpy.get).toHaveBeenCalledTimes(2); }); it("calls again when batch account changes", async () => { - const sizeSub = service.sizes.subscribe(); - expect(armSpy.get).toHaveBeenCalledTimes(1); - - const testBrazilAccount = new ArmBatchAccount({ - id: "/subs/sub-1/batchaccounts/acc-2", - name: "acc-2", - location: "brazilsouth", - properties: {} as any, - subscription: sub1, - }); + expect(armSpy.get).toHaveBeenCalledTimes(0); - const expectedOptionsParam = { - params: { - "$filter": `location eq '${testBrazilAccount.location}'` - } - }; + const sizeSub = service.sizes.subscribe(); + expect(armSpy.get).toHaveBeenCalledTimes(2); accountServiceSpy.currentAccount.next(testBrazilAccount); - expect(armSpy.get).toHaveBeenCalledTimes(2); - expect(armSpy.get).toHaveBeenCalledWith( - "subscriptions/sub1/providers/Microsoft.Compute/skus", expectedOptionsParam); + await service.sizes.pipe(take(1)).toPromise(); + expect(armSpy.get).toHaveBeenCalledTimes(4); + expect(armSpy.get).toHaveBeenCalledWith(brazilCloudServiceQuery); + expect(armSpy.get).toHaveBeenCalledWith(brazilVMQuery); sizeSub.unsubscribe(); }); @@ -119,16 +95,6 @@ describe("VMSizeService", () => { expect(sizes).not.toBeFalsy(); expect(sizes!.toJS()).toEqual([ - { - id: "standard_a0", - name: "Standard_A0", - numberOfCores: 1, - numberOfGpus: 0, - osDiskSizeInMB: 1047552, - resourceDiskSizeInMB: 20480, - memoryInMB: 768, - maxDataDiskCount: 1, - }, { id: "standard_a1", name: "Standard_A1", @@ -139,16 +105,6 @@ describe("VMSizeService", () => { memoryInMB: 1792, maxDataDiskCount: 2, }, - { - id: "small", - name: "small", - numberOfCores: 1, - numberOfGpus: 0, - osDiskSizeInMB: 1047552, - resourceDiskSizeInMB: 20480, - memoryInMB: 768, - maxDataDiskCount: 1, - }, { id: "standard_d1", name: "Standard_D1", @@ -166,7 +122,7 @@ describe("VMSizeService", () => { armSpy = { get: jasmine.createSpy("arm.get").and.returnValue(of(badResponseIsNaN)), }; - const serviceWithNaN = new VmSizeService(armSpy, githubDataSpy, accountServiceSpy); + const serviceWithNaN = new VmSizeService(armSpy, accountServiceSpy); const sizes = await serviceWithNaN.sizes.pipe(take(1)).toPromise(); expect(sizes).not.toBeFalsy(); @@ -188,7 +144,7 @@ describe("VMSizeService", () => { armSpy = { get: jasmine.createSpy("arm.get").and.returnValue(of(responseWithExtraCapability)), }; - const serviceWithExtraCap = new VmSizeService(armSpy, githubDataSpy, accountServiceSpy); + const serviceWithExtraCap = new VmSizeService(armSpy, accountServiceSpy); const sizes = await serviceWithExtraCap.sizes.pipe(take(1)).toPromise(); expect(sizes).not.toBeFalsy(); @@ -206,7 +162,7 @@ describe("VMSizeService", () => { ]); }); - it("fitlers the IAAS sizes", async () => { + it("filters the IAAS sizes", async () => { const sizes = await service.virtualMachineSizes.pipe(take(1)).toPromise(); expect(sizes).not.toBeFalsy(); expect(sizes!.toJS().map(x => x.id)).toEqual([ @@ -215,7 +171,7 @@ describe("VMSizeService", () => { ]); }); - it("fitlers the Cloud Service sizes", async () => { + it("filters the Cloud Service sizes", async () => { const sizes = await service.cloudServiceSizes.pipe(take(1)).toPromise(); expect(sizes).not.toBeFalsy(); expect(sizes!.toJS().map(x => x.id)).toEqual([ @@ -226,6 +182,10 @@ describe("VMSizeService", () => { it("returns null for the sizes when using local batch account", async () => { accountServiceSpy.currentAccount.next(new LocalBatchAccount({})); + const vmSizes = await service.virtualMachineSizes.pipe(take(1)).toPromise(); + expect(vmSizes).toBeFalsy(); + const cloudServiceSizes = await service.cloudServiceSizes.pipe(take(1)).toPromise(); + expect(cloudServiceSizes).toBeFalsy(); const sizes = await service.sizes.pipe(take(1)).toPromise(); expect(sizes).toBeFalsy(); }); diff --git a/src/app/services/compute/vm-size.service.ts b/src/app/services/compute/vm-size.service.ts index a0ad9930af..ae71882838 100644 --- a/src/app/services/compute/vm-size.service.ts +++ b/src/app/services/compute/vm-size.service.ts @@ -2,32 +2,27 @@ import { Injectable, OnDestroy } from "@angular/core"; import { log } from "@batch-flask/utils"; import { ArmBatchAccount, VmSize } from "app/models"; import { List } from "immutable"; -import { BehaviorSubject, Observable, Subject, combineLatest, of } from "rxjs"; +import { Observable, Subject, of, combineLatest } from "rxjs"; import { catchError, map, publishReplay, refCount, share, switchMap, take, takeUntil } from "rxjs/operators"; import { ArmHttpService } from "../arm-http.service"; import { BatchAccountService } from "../batch-account"; -import { computeUrl } from "../compute.service"; import { ArmListResponse } from "../core"; -import { GithubDataService } from "../github-data"; import { mapResourceSkuToVmSize } from "../../models/vm-size"; const includedVmsSizesPath = "data/vm-sizes-list.json"; -interface VmSizeData { - category: StringMap; - included: IncludedSizes; +export function supportedSkusUrl(subscriptionId: string, location: string) { + return `/subscriptions/${subscriptionId}/providers/Microsoft.Batch/locations/${location}` } -interface IncludedSizes { - all: string[]; - paas: string[]; - iaas: string[]; +interface VmSizeCategories { + category: StringMap; } @Injectable({ providedIn: "root" }) export class VmSizeService implements OnDestroy { /** - * All sizes + * All sizes combining cloud service and virtual machine sizes supported */ public sizes: Observable | null>; @@ -40,7 +35,194 @@ export class VmSizeService implements OnDestroy { * Only virtual machine sizes supported */ public virtualMachineSizes: Observable>; - public vmSizeCategories: Observable>; + + public vmSizeCategories = of({ + all: [".*"], + compute: [ + "^standard_f[0-9a-z]*$", + "^standard_f[0-9a-z]*_[v2]*$", + "^standard_f[0-9a-z]*_[v3]*$", + "standard_fx4mds", + "standard_fx12mds", + "standard_fx24mds", + "standard_fx36mds", + "standard_fx48mds" + ], + memory: [ + "standard_d11_v2", + "standard_d12_v2", + "standard_d13_v2", + "standard_d14_v2", + "standard_d15_v2", + + "standard_ds11_v2", + "standard_ds12_v2", + "standard_ds13_v2", + "standard_ds14_v2", + "standard_ds15_v2", + + "standard_e2_v3", + "standard_e4_v3", + "standard_e8_v3", + "standard_e16_v3", + "standard_e32_v3", + "standard_e64_v3", + + "standard_e2s_v3", + "standard_e4s_v3", + "standard_e8s_v3", + "standard_e16s_v3", + "standard_e32s_v3", + "standard_e48s_v3", + "standard_e64s_v3", + + "standard_e2a_v4", + "standard_e4a_v4", + "standard_e8a_v4", + "standard_e16a_v4", + "standard_e20a_v4", + "standard_e32a_v4", + "standard_e48a_v4", + "standard_e64a_v4", + "standard_e96a_v4", + + "standard_e2as_v4", + "standard_e4as_v4", + "standard_e8as_v4", + "standard_e16as_v4", + "standard_e20as_v4", + "standard_e32as_v4", + "standard_e48as_v4", + "standard_e64as_v4", + "standard_e96as_v4", + + "standard_e2d_v4", + "standard_e4d_v4", + "standard_e8d_v4", + "standard_e16d_v4", + "standard_e20d_v4", + "standard_e32d_v4", + "standard_e48d_v4", + "standard_e64d_v4", + + "standard_e2ds_v4", + "standard_e4ds_v4", + "standard_e8ds_v4", + "standard_e16ds_v4", + "standard_e20ds_v4", + "standard_e32ds_v4", + "standard_e48ds_v4", + "standard_e64ds_v4", + "standard_e80ids_v4", + + "standard_m8ms", + "standard_m16ms", + "standard_m32ms", + "standard_m32ls", + "standard_m32ts", + "standard_m64ls", + "standard_m64", + "standard_m64m", + "standard_m64s", + "standard_m64ms", + "standard_m128", + "standard_m128m", + "standard_m128ms", + "standard_m128s", + + "standard_m208ms_v2", + "standard_m208s_v2", + "standard_m416ms_v2", + "standard_m416s_v2" + ], + gpu: [ + "standard_nc6", + "standard_nc12", + "standard_nc24", + "standard_nc24r", + + "standard_nc6_promo", + "standard_nc12_promo", + "standard_nc24_promo", + "standard_nc24r_promo", + + "standard_nc6s_v2", + "standard_nc12s_v2", + "standard_nc24s_v2", + "standard_nc24rs_v2", + + "standard_nc6s_v3", + "standard_nc12s_v3", + "standard_nc24s_v3", + "standard_nc24rs_v3", + + "standard_nc4as_t4_v3", + "standard_nc8as_t4_v3", + "standard_nc16as_t4_v3", + "standard_nc64as_t4_v3", + + "standard_nd6s", + "standard_nd12s", + "standard_nd24s", + "standard_nd24rs", + + "standard_nd96asr_v4", + + "standard_nv6", + "standard_nv12", + "standard_nv24", + + "standard_nv6_promo", + "standard_nv12_promo", + "standard_nv24_promo", + + "standard_nv12s_v3", + "standard_nv24s_v3", + "standard_nv48s_v3", + + "standard_nv4as_v4", + "standard_nv8as_v4", + "standard_nv16as_v4", + "standard_nv32as_v4" + ], + hpc: [ + "standard_a8_v2", + "standard_a8m_v2", + "^standard_h[0-9a-z]*$", + "^standard_h[0-9a-z]*_promo$", + "^standard_h[bc][0-9a-z]*$", + "^standard_h[bc][0-9a-z]*_promo*$", + "^standard_h[bc][0-9a-z]*_[v2]*$", + "^standard_h[bc][0-9a-z]*_[v2]*_promo*$", + "standard_hb60rs", + "standard_hc44rs", + "standard_hb120rs_v3", + "standard_hb120_16rs_v3", + "standard_hb120_32rs_v3", + "standard_hb120_64rs_v3", + "standard_hb120_96rs_v3" + ], + standard: [ + "^standard_a[0-9a-z]*$", + "^standard_d[0-9a-z]*$", + "^basic_a[0-9a-z]*$", + "small", + "medium", + "large", + "extralarge", + "^a[1-9][0-9]*$" + ], + storage: [ + "^standard_l[0-9]*s_v2*$" + ], + fpga: [ + "standard_np10s", + "standard_np20s", + "standard_np40s" + ] + }) + + // delete bc you can get this information directly through API public additionalVmSizeCores = { extrasmall: 1, small: 1, @@ -49,55 +231,54 @@ export class VmSizeService implements OnDestroy { extralarge: 8, }; - private _includedSizes = new BehaviorSubject(null); - private _vmSizeCategories = new BehaviorSubject>(null); private _destroy = new Subject(); constructor( private arm: ArmHttpService, - private githubData: GithubDataService, accountService: BatchAccountService) { - this.loadVmSizeData(); - - this.sizes = accountService.currentAccount.pipe( + this.cloudServiceSizes = accountService.currentAccount.pipe( takeUntil(this._destroy), switchMap((account) => { if (!(account instanceof ArmBatchAccount)) { return of(null); } else { - return this._fetchVmSizesForAccount(account); + const cloudServiceUrl = `${supportedSkusUrl(account.subscription.subscriptionId, account.location)}/cloudServiceSkus?api-version=2021-06-01` + return this._fetchVmSkusForAccount(account, cloudServiceUrl); } }), publishReplay(1), refCount(), ); - const obs = combineLatest(this.sizes, this._includedSizes); - - this.cloudServiceSizes = obs.pipe( - map(([sizes, included]) => { - if (!included) { - return sizes; + this.virtualMachineSizes = accountService.currentAccount.pipe( + takeUntil(this._destroy), + switchMap((account) => { + if (!(account instanceof ArmBatchAccount)) { + return of(null); + } else { + const vmUrl = `${supportedSkusUrl(account.subscription.subscriptionId, account.location)}/virtualMachineSkus?api-version=2021-06-01` + return this._fetchVmSkusForAccount(account, vmUrl); } - return this.filterSizes(sizes, included.all.concat(included.paas)); }), publishReplay(1), refCount(), ); - this.virtualMachineSizes = obs.pipe( - map(([sizes, included]) => { - if (!included) { - return sizes; + this.sizes = combineLatest([this.cloudServiceSizes, this.virtualMachineSizes]).pipe( + map(([cloudServiceSizes, virtualMachineSizes]) => { + if (cloudServiceSizes && !virtualMachineSizes) { + return cloudServiceSizes; + } else if (!cloudServiceSizes && virtualMachineSizes) { + return virtualMachineSizes; + } else if (!cloudServiceSizes && !virtualMachineSizes) { + return null; } - return this.filterSizes(sizes, included.all.concat(included.iaas)); + return cloudServiceSizes.merge(virtualMachineSizes); }), publishReplay(1), refCount(), ); - - this.vmSizeCategories = this._vmSizeCategories.asObservable(); } public ngOnDestroy() { @@ -105,27 +286,6 @@ export class VmSizeService implements OnDestroy { this._destroy.complete(); } - public loadVmSizeData() { - this.githubData.get(includedVmsSizesPath).subscribe({ - next: (response: string) => { - const responseJson = JSON.parse(response); - const data: VmSizeData = { - category: responseJson.category, - included: { - all: responseJson.all, - paas: responseJson.paas, - iaas: responseJson.iaas, - }, - }; - this._vmSizeCategories.next(data.category); - this._includedSizes.next(data.included); - }, - error: (error) => { - log.error("Error loading included vm sizes from github", error); - }, - }); - } - public get(vmSize: string): Observable { return this.sizes.pipe( take(1), @@ -139,34 +299,9 @@ export class VmSizeService implements OnDestroy { share(), ); } - /** - * Filter the given list of vm sizes by including any patching the given patterns. - * @param sizes Sizes to filter - * @param includedPatterns List of regex patterns to include - */ - public filterSizes(sizes: List, includedPatterns: string[]): List { - if (!sizes) { - return null; - } - return List(sizes.filter((size) => { - for (const regex of includedPatterns) { - if (new RegExp(regex).test(size.name.toLowerCase())) { - return true; - } - } - return false; - })); - } - private _fetchVmSizesForAccount(account: ArmBatchAccount): Observable | null> { - const { subscription, location } = account; - const url = `${computeUrl(subscription.subscriptionId)}/skus`; - const options = { - params: { - "$filter": `location eq '${location}'` - } - }; - return this.arm.get>(url, options).pipe( + private _fetchVmSkusForAccount(account: ArmBatchAccount, query: string): Observable | null> { + return this.arm.get>(query).pipe( map((response) => { return mapResourceSkuToVmSize(response.value); }), diff --git a/src/app/services/compute/vmsize_sample_responses.ts b/src/app/services/compute/vmsize_sample_responses.ts index f734d1479b..2abf38f87b 100644 --- a/src/app/services/compute/vmsize_sample_responses.ts +++ b/src/app/services/compute/vmsize_sample_responses.ts @@ -1,4 +1,4 @@ -export const vmSizeSampleResponse = { +export const cloudServiceResponse = { "value": [ { "resourceType": "virtualMachines", @@ -29,34 +29,20 @@ export const vmSizeSampleResponse = { { "name": "GPUs", "value": "0" - }, + } ], "locationInfo": [ { "location": "westus", "zones": [ - "2", - "1" - ], - "zoneDetails": [ - { - "name": [ - "2" - ], - "capabilities": [ - { - "name": "UltraSSDAvailable", - "value": "True" - } - ] - } + "1", ] } ], - "name": "Standard_A0", + "name": "small", "tier": "Standard", - "size": "A0", - "family": "standardA0_A7Family" + "size": "small", + "family": "standardSmallFamily" }, { "resourceType": "virtualMachines", @@ -66,7 +52,7 @@ export const vmSizeSampleResponse = { "capabilities": [ { "name": "MaxResourceVolumeMB", - "value": "71680" + "value": "51200" }, { "name": "OSVhdSizeMB", @@ -78,32 +64,36 @@ export const vmSizeSampleResponse = { }, { "name": "MemoryGB", - "value": "1.75" + "value": "3.5" }, { "name": "MaxDataDiskCount", - "value": "2" + "value": "4" }, { "name": "GPUs", - "value": "0" + "value": "2" } ], "locationInfo": [ { - "location": "westus", + "location": "eastus", "zones": [ "1", - "2", - "3" - ] + ], + "zoneDetails": [] } ], - "name": "Standard_A1", + "name": "Standard_D1", "tier": "Standard", - "size": "A1", - "family": "standardA0_A7Family" - }, + "size": "D1", + "family": "standardDFamily" + } + ] +} + +export const virtualMachineResponse = { + "value": [ { "resourceType": "virtualMachines", "locations": [ @@ -112,7 +102,7 @@ export const vmSizeSampleResponse = { "capabilities": [ { "name": "MaxResourceVolumeMB", - "value": "20480" + "value": "71680" }, { "name": "OSVhdSizeMB", @@ -124,11 +114,11 @@ export const vmSizeSampleResponse = { }, { "name": "MemoryGB", - "value": "0.75" + "value": "1.75" }, { "name": "MaxDataDiskCount", - "value": "1" + "value": "2" }, { "name": "GPUs", @@ -140,13 +130,15 @@ export const vmSizeSampleResponse = { "location": "westus", "zones": [ "1", + "2", + "3" ] } ], - "name": "small", + "name": "Standard_A1", "tier": "Standard", - "size": "small", - "family": "standardSmallFamily" + "size": "A1", + "family": "standardA0_A7Family" }, { "resourceType": "virtualMachines", @@ -193,8 +185,7 @@ export const vmSizeSampleResponse = { "size": "D1", "family": "standardDFamily" } - ], - "nextLink": null + ] } export const badResponseIsNaN = {