Add Batch RLC to service package & Add node service (#2853)

This commit is contained in:
Haopeng Wang 2024-01-24 14:15:45 +08:00 коммит произвёл GitHub
Родитель a7a1e45086
Коммит 1fafbc66ab
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
83 изменённых файлов: 15723 добавлений и 4349 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -18,3 +18,4 @@ Localize/out/
/packages/*/src/generated/*
/util/bux/__tests__/loc-source/generated
/web/src/generated/*
TempTypeSpecFiles

Просмотреть файл

@ -23,11 +23,6 @@ steps:
packagePath: ./packages/bonito-ui
packageName: "@azure/bonito-ui"
- template: ./publish-npm-package.yml
parameters:
packagePath: ./packages/arm-batch-rest
packageName: "@batch/arm-batch-rest"
- template: ./publish-npm-package.yml
parameters:
packagePath: ./packages/service

Просмотреть файл

@ -29,6 +29,9 @@ const baseConfig = {
// (See https://github.com/facebook/react/issues/13991)
react: path.resolve("../node_modules/react"),
"react-dom": path.resolve('../node_modules/react-dom'),
// Since we are patching the core-util module' isNode variable,
// we need to make sure that the patched version is used by all
"@azure/core-util": path.resolve('./node_modules/@azure/core-util'),
},
},

1
desktop/package-lock.json сгенерированный
Просмотреть файл

@ -20,6 +20,7 @@
"@angular/platform-browser-dynamic": "^11.0.0",
"@angular/platform-server": "^11.0.0",
"@angular/router": "^11.0.0",
"@azure/core-util": "1.4.0",
"@azure/msal-node": "^1.14.6",
"@azure/storage-blob": "^12.11.0",
"@electron/remote": "^2.0.10",

Просмотреть файл

@ -187,6 +187,7 @@
"yesno": "^0.0.1"
},
"dependencies": {
"@azure/core-util": "1.4.0",
"@angular/animations": "^11.0.0",
"@angular/cdk": "^11.0.0",
"@angular/common": "^11.0.0",
@ -247,6 +248,7 @@
},
"overrides": {
"json5": "^2.2.3",
"ajv": "^6.12.6"
"ajv": "^6.12.6",
"@azure/core-util": "1.4.0"
}
}

Просмотреть файл

@ -30,14 +30,9 @@ describe("BatchExplorerHttpClient", () => {
expect(fakeAuthService.getAccessToken).toHaveBeenCalledWith(
TenantPlaceholders.common);
expect(fakeFetchHttpClient.fetch).toHaveBeenCalledWith(
"/subscriptions",
{
headers: {
Authorization: "Token1Type token1"
}
}
);
const [subscriptionUrl, requestProps] = fakeFetchHttpClient.fetch.calls.argsFor(0);
expect(subscriptionUrl).toEqual("/subscriptions");
expect(requestProps.headers.get('authorization')).toEqual("Token1Type token1");
});
it("uses the common tenant regardless of subscription in URL",
async () => {

Просмотреть файл

@ -25,12 +25,27 @@ export default class BatchExplorerHttpClient extends AbstractHttpClient {
const accessToken: AccessToken =
await this.authService.getAccessToken(tenantId);
const authRequestProps = {...requestProps};
if (!authRequestProps.headers) {
authRequestProps.headers = {};
const headers: Headers = new Headers();
if (requestProps?.headers) {
if (typeof requestProps.headers.forEach === "function") {
// Headers object
requestProps.headers.forEach((value, key) => {
headers.set(key, value);
});
} else {
// Map of headers
const headerMap = requestProps.headers as Record<string, string>;
for (const [k, v] of Object.entries(headerMap)) {
headers.set(k, v);
}
}
}
authRequestProps.headers["Authorization"] =
`${accessToken.tokenType} ${accessToken.accessToken}`;
return this._delegate.fetch(urlOrRequest, authRequestProps);
headers.set("Authorization", `${accessToken.tokenType} ${accessToken.accessToken}`);
return this._delegate.fetch(urlOrRequest, {
...requestProps,
headers,
});
}
}

Просмотреть файл

@ -14,7 +14,7 @@ import { DefaultFormLayoutProvider } from "@azure/bonito-ui/lib/components/form"
import { BrowserDependencyName, BrowserEnvironmentConfig, DefaultBrowserEnvironment } from "@azure/bonito-ui/lib/environment";
import BatchExplorerHttpClient from "@batch-flask/core/batch-explorer-http-client";
import { BatchBrowserDependencyFactories, BatchFormControlResolver } from "@batch/ui-react";
import { LivePoolService } from "@batch/ui-service";
import { LiveNodeService, LivePoolService } from "@batch/ui-service";
import { BatchDependencyName } from "@batch/ui-service/lib/environment";
import { DesktopLocalizer } from "app/localizer/desktop-localizer";
import { AppTranslationsLoaderService, AuthService, BatchExplorerService } from "app/services";
@ -44,6 +44,8 @@ export function initDesktopEnvironment(
new LiveLocationService(),
[BatchDependencyName.PoolService]: () =>
new LivePoolService(),
[BatchDependencyName.NodeService]: () =>
new LiveNodeService(),
[DependencyName.Notifier]: () =>
new AlertNotifier(), // TODO: update with real notification implementation
[DependencyName.ResourceGroupService]: () =>

1199
eng/emitter-package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

14
eng/emitter-package.json Normal file
Просмотреть файл

@ -0,0 +1,14 @@
{
"name": "typescript-emitter-package",
"main": "dist/src/index.js",
"dependencies": {
"@azure-tools/typespec-ts": "0.19.0",
"@azure-tools/typespec-azure-core": "0.35.0",
"@azure-tools/typespec-autorest": "0.35.0",
"@azure-tools/typespec-client-generator-core": "0.35.0",
"@typespec/compiler": "0.49.0",
"@typespec/http": "0.49.0",
"@typespec/rest": "0.49.0",
"@typespec/versioning": "0.49.0"
}
}

Просмотреть файл

@ -1,7 +0,0 @@
{
"extends": "./tsconfig.common.json",
"compilerOptions": {
"tsBuildInfoFile": "../build/cache/ts.build.buildinfo"
},
"exclude": ["../**/__mocks__/**/*"]
}

Просмотреть файл

@ -1,9 +0,0 @@
{
"extends": "./tsconfig.common.json",
"compilerOptions": {
"module": "CommonJS",
"outDir": "../lib-cjs",
"tsBuildInfoFile": "../build/cache/ts.cjs.buildinfo"
},
"exclude": ["../**/__mocks__/**/*"]
}

Просмотреть файл

@ -1,9 +0,0 @@
{
"extends": "../../../util/common-config/tsconfig-base.json",
"compilerOptions": {
"outDir": "../lib",
"rootDir": "../src/",
"typeRoots": ["../node_modules/@types"]
},
"include": ["../src/"]
}

Просмотреть файл

@ -1,9 +0,0 @@
/* eslint-env node */
/* eslint-disable @typescript-eslint/no-var-requires */
module.exports = require("@batch/common-config/jest-common").createConfig(
"arm-batch-rest",
require("./tsconfig.json"),
{
setupFilesAfterEnv: ["<rootDir>/src/__tests__/setup-tests.ts"],
}
);

4020
packages/arm-batch-rest/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,92 +0,0 @@
{
"name": "@batch/arm-batch-rest",
"sdk-type": "mgmt",
"author": "Microsoft Corporation",
"version": "1.0.1",
"description": "A generated Rest Level Client SDK for the Batch Management Plane.",
"keywords": [
"node",
"azure",
"cloud",
"typescript",
"browser",
"isomorphic"
],
"license": "MIT",
"main": "./lib-cjs/index.js",
"module": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/Azure/BatchExplorer"
},
"files": [
"lib",
"lib-cjs"
],
"engines": {
"node": ">=18.0.0"
},
"test": "jest",
"scripts": {
"build": "npm run compile",
"build:clean": "run-s clean compile",
"build:test": "run-s build test",
"compile": "run-p compile:*",
"compile:esm": "tsc -b ./config/tsconfig.build.json",
"compile:cjs": "tsc -b ./config/tsconfig.cjs.json",
"clean": "run-p clean:*",
"clean:build": "bux rmrf ./build",
"clean:esm": "bux rmrf ./lib",
"clean:cjs": "bux rmrf ./lib-cjs",
"generate:client": "autorest --typescript swagger/README.md",
"lint": "eslint . --max-warnings 0",
"test": "jest",
"test:all": "npm run test:coverage",
"test:coverage": "jest --collect-coverage",
"test:watch": "jest --watch",
"watch": "run-p \"compile:* -- --watch --preserveWatchOutput\"",
"workspace:build": "npm run build",
"workspace:build:clean": "npm run build:clean",
"workspace:build:desktop": "npm run build",
"workspace:build:lib": "npm run build",
"workspace:build:web": "npm run build",
"workspace:build:package": "npm run build:clean",
"workspace:build:prod": "npm run build:clean",
"workspace:build:test": "npm run build:test",
"workspace:clean": "npm run clean",
"workspace:launch:desktop": "npm run watch",
"workspace:launch:web": "npm run watch",
"workspace:lint": "npm run lint",
"workspace:lint:fix": "npm run lint -- --fix",
"workspace:start:desktop": "npm run watch",
"workspace:start:web": "npm run watch",
"workspace:test": "npm run test",
"workspace:test:all": "npm run test:all",
"workspace:test:desktop": "npm run test",
"workspace:test:lib": "npm run test",
"workspace:test:lib:all": "npm run test:all",
"workspace:test:web": "npm run test",
"workspace:test:web:all": "npm run test:all",
"workspace:watch:lib": "npm run watch"
},
"sideEffects": false,
"autoPublish": false,
"dependencies": {
"@azure/bonito-core": "^1.0.0",
"@azure-rest/core-client": "1.0.0-beta.10",
"@azure/core-auth": "^1.3.0",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.2.0",
"@azure/core-rest-pipeline": "^1.8.0"
},
"devDependencies": {
"@batch/common-config": "^1.0.0",
"@types/jest": "^29.2.4",
"@types/node": "20.5.4",
"autorest": "3.6.3",
"jest": "^29.3.1",
"jest-junit": "^12.2.0",
"ts-jest": "^29.0.3"
}
}

Просмотреть файл

@ -1,10 +0,0 @@
import { destroyEnvironment } from "@azure/bonito-core";
afterEach(() => {
jest.resetAllMocks();
destroyEnvironment();
});
afterAll(() => {
jest.restoreAllMocks();
});

Просмотреть файл

@ -1,6 +0,0 @@
{
"extends": "./config/tsconfig.common.json",
"compilerOptions": {
"tsBuildInfoFile": "./build/cache/ts.buildinfo"
}
}

Просмотреть файл

@ -78,5 +78,6 @@
"lib",
"lib-cjs",
"resources"
]
],
"sideEffects": false
}

Просмотреть файл

@ -91,5 +91,6 @@
"lib",
"lib-cjs",
"resources"
]
],
"sideEffects": false
}

Просмотреть файл

@ -89,5 +89,6 @@
"lib",
"lib-cjs",
"resources"
]
],
"sideEffects": false
}

Просмотреть файл

@ -94,5 +94,6 @@
"lib",
"lib-cjs",
"resources"
]
],
"sideEffects": false
}

Просмотреть файл

@ -136,6 +136,7 @@ export class UpdateNodeCommsAction extends AbstractAction<UpdateNodeCommsFormVal
async onExecute(values: UpdateNodeCommsFormValues): Promise<void> {
await this._poolService.patch(
this._poolArmId,
{
id: this._poolArmId,
properties: {

Просмотреть файл

@ -0,0 +1,14 @@
# overrided options for emitter: @azure-tools/typespec-ts
# see details: https://www.npmjs.com/package/@azure-tools/typespec-ts
$options = (
"generateMetadata=false; " +
"azureSdkForJs=false; " +
"generateTest=false; "
)
npx tsp-client update `
--emitter-options $options `
--output-dir "./src/internal/batch-rest/generated"

972
packages/service/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -25,7 +25,8 @@
"clean:build": "bux rmrf ./build",
"clean:esm": "bux rmrf ./lib",
"clean:cjs": "bux rmrf ./lib-cjs",
"clean:generated": "bux rmrf ./src/ui-service/generated",
"generate:arm-client": "autorest --typescript swagger/README.md",
"generate:client": "powershell -ExecutionPolicy Bypass -File ./generate-client.ps1",
"test": "jest",
"test:coverage": "jest --collect-coverage",
"test:all": "npm run test:coverage",
@ -63,13 +64,21 @@
"tslib": "~2.3.1"
},
"dependencies": {
"@azure-rest/core-client": "^1.1.4",
"@azure/bonito-core": "^1.0.0",
"@batch/arm-batch-rest": "^1.0.0"
"@azure/core-auth": "^1.3.0",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.2.0",
"@azure/core-rest-pipeline": "^1.8.0",
"@azure/logger": "^1.0.0"
},
"devDependencies": {
"@azure-tools/typespec-client-generator-cli": "^0.3.0",
"@batch/common-config": "^1.0.0",
"@types/jest": "^27.0.1",
"@types/node": "20.5.4",
"@typespec/compiler": "^0.50.0",
"autorest": "^3.6.3",
"jest": "^27.1.0",
"jest-junit": "^12.2.0",
"ts-jest": "^27.0.5"
@ -78,5 +87,6 @@
"lib",
"lib-cjs",
"resources"
]
],
"sideEffects": false
}

Просмотреть файл

@ -0,0 +1,45 @@
# Batch Service Libaray
This package intended to act as a decoupled data access & business logic layer for the Batch service, which also including two Rest Level Client (RLC) for the Batch Data plane and Batch Management plane.
RLC (Rest Level Client) is an Azure specific SDK flavor that emphasizes seamless developer experience by acting as a layer above raw HTTP calls. One of the major benefits of this SDK type is that they provide a compact, browser friendly bundle size footprint by relying on an abstract REST client and contains Batch specific Typescript type definitions as oppose to exportable classes. More information about RLCs can be found [here](https://devblogs.microsoft.com/azure-sdk/azure-rest-libraries-for-javascript/).
## Development Prerequisites
Before developing against this library, please consult the __Developer Prerequisites__ section of `<ROOT_DIR>/packages/README.md`.
## Package Layout
- `src/internal/batch-rest` contains the Batch Data plane RLC
- `src/internal/arm-batch-rest` contains the Batch Management plane RLC
- `src/internal/client-http` contains the HTTP client code that is shared between the Batch Data plane and Batch Management plane RLCs
- `swagger` - This subdirectory contains the swagger configuration file containing documented autorest command options to make the __Batch Management RLC__ code regeneration process easier to invoke in case there is a need to refresh the rest api input file or other changes. The associated README.md configuration file contains autorest command options such as: package name and version, swagger input file, source code folder path, client authentication customization, etc. One of the command options within the file is the __input-file__ option which is a link to the openAPI Batch swagger file under the public [Azure Rest API Spec repo](https://github.com/Azure/azure-rest-api-specs). In order to regenerate the SDK to pick up the latest API swagger definitions, you will need to change the input-file path to point to the file denoted under the latest API version.
- `<ROOT_DIR>/eng/emitter-package.json` - This file is used by `tsp-client` to install the required dependencies to setup the local TypeSpec project for generating the Batch Data plane RLC, see more details in [Azure JS SDK RLC quickstart](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/RLC-quickstart.md) and [tsp-client npm readme](https://www.npmjs.com/package/@azure-tools/typespec-client-generator-cli)
## Generating the Batch Data Plane RLC
Batch Data Plane RLC is generated based on our TypeSpec files. First make sure `src\internal\batch-rest\generated\tsp-location.yaml` is updated with the __github__ repo and the commit hash which has the targeted `tspconfig.yml` and `*.tsp` files. Then then run the following from the root of the `service` package:
```shell
npm run generate:client
```
This will execute `generate-client.ps1` which runs `tsp-client` command to fetch the remote `tspconfig.yml` and `*.tsp` files and install the required dependencies for a local TypeSpec project in `src/internal/arm-batch-rest/generated/TempTypeSpecFiles`, which shouldn't be checked in as it's a temporaty project. Then, the `tsp-client` will generate the Batch Data plane RLC code based on this local TypeSpec project, see more details in the [tsp-client npm readme](https://www.npmjs.com/package/@azure-tools/typespec-client-generator-cli)
- `src/internal/batch-rest/generated/src` - This holds the autogenerated code such as obtaining the client and Batch specific modeless interfaces. These files should generally not be modified manually.
## Generating the Batch Management RLC
Batch Management RLC is generated based on swagger files by autorest. First make sure `input-file` in `swagger/README.md` is pointing to the latest API version. Then then run the following from the root of the `service` package:
```shell
npm run generate:arm-client
```
This will parse the command options from the README and regenerate the SDK code
- `src/internal/arm-batch-rest/generated` - This holds the swagger autogenerated code such as obtaining the client and Batch specific modeless interfaces. These files should generally not be modified manually.

Просмотреть файл

@ -0,0 +1,83 @@
import { parseBatchAccountIdInfo, parsePoolArmIdInfo } from "../utils";
describe("parse arm id", () => {
it("should parse a valid arm id", () => {
const batchAccountId =
"/subscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba";
const poolArmId =
"/subscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba/pools/pool";
const result1 = parseBatchAccountIdInfo(batchAccountId);
expect(result1).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
});
const result2 = parsePoolArmIdInfo(poolArmId);
expect(result2).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
poolName: "pool",
});
});
it("should parse a valid absolute url", () => {
const batchAccountId =
"https://example.com/subscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba";
const poolArmId =
"https://example.com/subscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba/pools/pool";
const result1 = parseBatchAccountIdInfo(batchAccountId);
expect(result1).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
});
const result2 = parsePoolArmIdInfo(poolArmId);
expect(result2).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
poolName: "pool",
});
});
it("should parse with case-insensitive", () => {
const batchAccountId =
"/SuBscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba";
const poolArmId =
"/SuBscriptions/123/resourceGroups/rg/providers/Microsoft.Batch/batchAccounts/ba/pools/pool";
const result1 = parseBatchAccountIdInfo(batchAccountId);
expect(result1).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
});
const result2 = parsePoolArmIdInfo(poolArmId);
expect(result2).toEqual({
subscriptionId: "123",
resourceGroupName: "rg",
batchAccountName: "ba",
poolName: "pool",
});
});
it("should throw an error for an invalid batch account id", () => {
const batchAccountId = "/invalid/batch/account/id";
expect(() => parseBatchAccountIdInfo(batchAccountId)).toThrowError(
"Unable to parse batch account id: /invalid/batch/account/id"
);
const poolArmId = "/invalid/pool/arm/id";
expect(() => parsePoolArmIdInfo(poolArmId)).toThrowError(
"Unable to parse pool ARM id: /invalid/pool/arm/id"
);
});
});

Просмотреть файл

@ -1 +1 @@
export { BatchAccountOutput } from "@batch/arm-batch-rest";
export { BatchAccountOutput } from "../internal/arm-batch-rest";

Просмотреть файл

@ -0,0 +1 @@
export * from "./internal/arm-batch-rest/generated/outputModels";

Просмотреть файл

@ -0,0 +1 @@
export * from "./internal/batch-rest/generated/src/outputModels";

Просмотреть файл

@ -1,4 +1,4 @@
export const BatchApiVersion = {
arm: `2022-10-01`,
data: `2022-10-01.16.0`,
arm: `2023-05-01`,
data: `2023-05-01.17.0`,
};

Просмотреть файл

@ -1,10 +1,13 @@
import { DependencyFactories } from "@azure/bonito-core/lib/environment";
import { NodeService } from "../node";
import { PoolService } from "../pool";
export enum BatchDependencyName {
PoolService = "poolService",
NodeService = "nodeService",
}
export interface BatchDependencyFactories extends DependencyFactories {
[BatchDependencyName.PoolService]: () => PoolService;
[BatchDependencyName.NodeService]: () => NodeService;
}

Просмотреть файл

@ -2,4 +2,5 @@ export * from "./view";
export * from "./account";
export * from "./certificate";
export * from "./pool";
export * from "./node";
export * from "./constants";

Просмотреть файл

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import generateBatchManagementClient from "../client";
import { createARMBatchClient } from "../client";
import {
BatchAccountListResultOutput,
BatchManagementClient,
@ -15,7 +15,7 @@ import {
BATCH_API_VERSION,
getUrlBatchAccountPath,
getUrlPoolPath,
} from "./utils/client";
} from "../__tests__/utils/client";
import {
DependencyName,
getMockEnvironment,
@ -68,7 +68,7 @@ describe("Batch Management Client With Mock Http Client Test", () => {
DependencyName.HttpClient
);
batchClient = generateBatchManagementClient();
batchClient = createARMBatchClient();
});
describe("Basic Pool operations", () => {

Просмотреть файл

@ -8,9 +8,9 @@ import { TokenCredential } from "@azure/core-auth";
import { ClientOptions } from "@azure-rest/core-client";
import { BatchManagementClient } from "./generated";
import createClient from "./generated/batchManagementClient";
import { BatchHttpClient } from "./http/batch-http-client";
import { BatchHttpClient } from "../client-http/batch-http-client";
export default function generateBatchManagementClient(
export function createARMBatchClient(
options: ClientOptions = {},
credential?: TokenCredential
): BatchManagementClient {
@ -18,6 +18,9 @@ export default function generateBatchManagementClient(
options = {
...options,
httpClient: new BatchHttpClient(),
retryOptions: {
maxRetries: 0,
},
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any

Просмотреть файл

@ -738,7 +738,7 @@ export interface StartTask {
environmentSettings?: Array<EnvironmentSetting>;
/** If omitted, the task runs as a non-administrative user unique to the task. */
userIdentity?: UserIdentity;
/** The Batch service retries a task if its exit code is nonzero. Note that this value specifically controls the number of retries. The Batch service will try the task once, and may then retry up to this limit. For example, if the maximum retry count is 3, Batch tries the task up to 4 times (one initial try and 3 retries). If the maximum retry count is 0, the Batch service does not retry the task. If the maximum retry count is -1, the Batch service retries the task without limit. */
/** The Batch service retries a task if its exit code is nonzero. Note that this value specifically controls the number of retries. The Batch service will try the task once, and may then retry up to this limit. For example, if the maximum retry count is 3, Batch tries the task up to 4 times (one initial try and 3 retries). If the maximum retry count is 0, the Batch service does not retry the task. If the maximum retry count is -1, the Batch service retries the task without limit. Default is 0. */
maxTaskRetryCount?: number;
/** If true and the start task fails on a compute node, the Batch service retries the start task up to its maximum retry count (maxTaskRetryCount). If the task has still not completed successfully after all retries, then the Batch service marks the compute node unusable, and will not schedule tasks to it. This condition can be detected via the node state and scheduling error detail. If false, the Batch service will not wait for the start task to complete. In this case, other tasks can start executing on the compute node while the start task is still running; and even if the start task fails, new tasks will continue to be scheduled on the node. The default is true. */
waitForSuccess?: boolean;

Просмотреть файл

@ -185,16 +185,14 @@ export interface PrivateLinkServiceConnectionStateOutput {
/** A definition of an Azure resource. */
export interface ProxyResourceOutput {
// KLUDGE (dawatrou): Manually fixed up 'id', 'name' and 'type' to be non-nullable.
// Need to follow up with the JS SDK team about this.
/** The ID of the resource. */
id: string;
/** The name of the resource. */
name: string;
/** The type of the resource. */
type: string;
/** The ETag of the resource, used for concurrency statements. */
etag?: string;
/** The ID of the resource. */
id?: string;
/** The name of the resource. */
name?: string;
/** The type of the resource. */
type?: string;
/** The ETag of the resource, used for concurrency statements. */
etag?: string;
}
/** Contains information about the auto-storage account associated with a Batch account. */
@ -863,20 +861,16 @@ export interface TaskSchedulingPolicyOutput {
/** Properties used to create a user on an Azure Batch node. */
export interface UserAccountOutput {
/** The name of the user account. Names can contain any Unicode characters up to a maximum length of 20. */
name: string;
/**
* KLUDGE (dawatrou): Manually removed incorred "password" property. This is a secret and isn't returned by the service.
* This should be fixed in the Swagger so x-ms-secret is true.
* The password for the user account.
* */
// password: string;
/** nonAdmin - The auto user is a standard user without elevated access. admin - The auto user is a user with elevated access and operates with full Administrator permissions. The default value is nonAdmin. */
elevationLevel?: "NonAdmin" | "Admin";
/** This property is ignored if specified on a Windows pool. If not specified, the user is created with the default options. */
linuxUserConfiguration?: LinuxUserConfigurationOutput;
/** This property can only be specified if the user is on a Windows pool. If not specified and on a Windows pool, the user is created with the default options. */
windowsUserConfiguration?: WindowsUserConfigurationOutput;
/** The name of the user account. Names can contain any Unicode characters up to a maximum length of 20. */
name: string;
/** The password for the user account. */
password: string;
/** nonAdmin - The auto user is a standard user without elevated access. admin - The auto user is a user with elevated access and operates with full Administrator permissions. The default value is nonAdmin. */
elevationLevel?: "NonAdmin" | "Admin";
/** This property is ignored if specified on a Windows pool. If not specified, the user is created with the default options. */
linuxUserConfiguration?: LinuxUserConfigurationOutput;
/** This property can only be specified if the user is on a Windows pool. If not specified and on a Windows pool, the user is created with the default options. */
windowsUserConfiguration?: WindowsUserConfigurationOutput;
}
/** Properties used to create a user account on a Linux node. */
@ -913,7 +907,7 @@ export interface StartTaskOutput {
environmentSettings?: Array<EnvironmentSettingOutput>;
/** If omitted, the task runs as a non-administrative user unique to the task. */
userIdentity?: UserIdentityOutput;
/** The Batch service retries a task if its exit code is nonzero. Note that this value specifically controls the number of retries. The Batch service will try the task once, and may then retry up to this limit. For example, if the maximum retry count is 3, Batch tries the task up to 4 times (one initial try and 3 retries). If the maximum retry count is 0, the Batch service does not retry the task. If the maximum retry count is -1, the Batch service retries the task without limit. */
/** The Batch service retries a task if its exit code is nonzero. Note that this value specifically controls the number of retries. The Batch service will try the task once, and may then retry up to this limit. For example, if the maximum retry count is 3, Batch tries the task up to 4 times (one initial try and 3 retries). If the maximum retry count is 0, the Batch service does not retry the task. If the maximum retry count is -1, the Batch service retries the task without limit. Default is 0. */
maxTaskRetryCount?: number;
/** If true and the start task fails on a compute node, the Batch service retries the start task up to its maximum retry count (maxTaskRetryCount). If the task has still not completed successfully after all retries, then the Batch service marks the compute node unusable, and will not schedule tasks to it. This condition can be detected via the node state and scheduling error detail. If false, the Batch service will not wait for the start task to complete. In this case, other tasks can start executing on the compute node while the start task is still running; and even if the start task fails, new tasks will continue to be scheduled on the node. The default is true. */
waitForSuccess?: boolean;

Просмотреть файл

@ -7,5 +7,4 @@ export * from "./generated/isUnexpected";
export * from "./generated/models";
export * from "./generated/outputModels";
export * from "./generated/paginateHelper";
export * from "./generated/pollingHelper";
export * from "./client";

Просмотреть файл

@ -0,0 +1,231 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { createBatchClient } from "../client";
import {
DependencyName,
getMockEnvironment,
initMockEnvironment,
} from "@azure/bonito-core/lib/environment";
import { MockHttpClient, MockHttpResponse } from "@azure/bonito-core/lib/http";
import {
BatchClient,
BatchJobListResultOutput,
BatchJobOutput,
BatchNodeListResultOutput,
BatchNodeVMExtensionListResultOutput,
CreateJobParameters,
} from "../generated/src";
const batchAccountEndpoint = "https://batchaccount.eastus2.batch.azure.com";
const BATCH_API_VERSION = "2023-05-01.17.0";
describe("Batch Client With Mock Http Client Test", () => {
let batchClient: BatchClient;
let mockClient: MockHttpClient;
beforeEach(() => {
initMockEnvironment();
mockClient = getMockEnvironment().getInjectable(
DependencyName.HttpClient
);
batchClient = createBatchClient(batchAccountEndpoint);
});
describe("Basic Job operations", () => {
test("Create Batch Job", async () => {
const jobPath = "/jobs";
const requestUrlJobPath = `${batchAccountEndpoint}${jobPath}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlJobPath, {
status: 201,
headers: {
"Content-Type": "application/json",
},
});
const jobParams: CreateJobParameters = {
contentType: "application/json; odata=minimalmetadata",
body: {
id: "test-job-id",
poolInfo: { poolId: "test-pool-id" },
},
};
mockClient.addExpected(mockResponse, {
method: "POST",
body: JSON.stringify(jobParams.body),
});
const response = await batchClient.path("/jobs").post(jobParams);
expect(response.status).toEqual("201");
});
test("Get Batch Job", async () => {
const jobId = "test-job-id";
const jobPath = "/jobs/{jobId}";
const requestUrlJobPath = `${batchAccountEndpoint}${jobPath.replace(
"{jobId}",
jobId
)}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlJobPath, {
status: 200,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(<BatchJobOutput>{
id: jobId,
poolInfo: { poolId: "test-pool-id" },
}),
});
mockClient.addExpected(mockResponse, {
method: "GET",
});
const response = await batchClient.path(jobPath, jobId).get();
expect(response.status).toEqual("200");
const body = response.body as BatchJobOutput;
expect(body.id).toEqual(jobId);
expect(body?.poolInfo.poolId).toEqual("test-pool-id");
});
test("list job", async () => {
const jobPath = "/jobs";
const requestUrlJobPath = `${batchAccountEndpoint}${jobPath}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlJobPath, {
status: 200,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(<BatchJobListResultOutput>{
value: [
{
id: "test-job-id",
poolInfo: { poolId: "test-pool-id" },
},
],
}),
});
mockClient.addExpected(mockResponse, {
method: "GET",
});
const response = await batchClient.path(jobPath).get();
expect(response.status).toEqual("200");
const body = response.body as BatchJobListResultOutput;
expect(body?.value?.length).toEqual(1);
expect(body?.value?.[0].id).toEqual("test-job-id");
expect(body?.value?.[0]?.poolInfo.poolId).toEqual("test-pool-id");
});
test("delete job", async () => {
const jobId = "test-job-id";
const jobPath = "/jobs/{jobId}";
const requestUrlJobPath = `${batchAccountEndpoint}${jobPath.replace(
"{jobId}",
jobId
)}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlJobPath, {
status: 204,
headers: {
"Content-Type": "application/json",
},
});
mockClient.addExpected(mockResponse, {
method: "DELETE",
});
const response = await batchClient.path(jobPath, jobId).delete();
expect(response.status).toEqual("204");
});
});
describe("Basic Node operations", () => {
test("list compute nodes", async () => {
const poolId = "test-pool-id";
const nodePath = "/pools/{poolId}/nodes";
const requestUrlNodePath = `${batchAccountEndpoint}${nodePath.replace(
"{poolId}",
poolId
)}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlNodePath, {
status: 200,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(<BatchNodeListResultOutput>{
value: [
{
id: "test-node-id",
state: "idle",
},
],
}),
});
mockClient.addExpected(mockResponse, {
method: "GET",
});
const response = await batchClient.path(nodePath, poolId).get();
expect(response.status).toEqual("200");
const body = response.body as BatchNodeListResultOutput;
expect(body?.value?.length).toEqual(1);
expect(body?.value?.[0]?.id).toEqual("test-node-id");
expect(body.value?.[0]?.state).toEqual("idle");
});
});
test("list compute node extensions", async () => {
const poolId = "test-pool-id";
const nodeId = "test-node-id";
const nodeExtensionPath = "/pools/{poolId}/nodes/{nodeId}/extensions";
const requestUrlNodeExtensionPath = `${batchAccountEndpoint}${nodeExtensionPath
.replace("{poolId}", poolId)
.replace("{nodeId}", nodeId)}?api-version=${BATCH_API_VERSION}`;
const mockResponse = new MockHttpResponse(requestUrlNodeExtensionPath, {
status: 200,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(<BatchNodeVMExtensionListResultOutput>{
value: [
{
vmExtension: {
name: "extension-name",
type: "extension-type",
publisher: "extension-publisher",
typeHandlerVersion: "1.0",
},
provisioningState: "success",
},
],
}),
});
mockClient.addExpected(mockResponse, {
method: "GET",
});
const response = await batchClient
.path(nodeExtensionPath, poolId, nodeId)
.get();
expect(response.status).toEqual("200");
const body = response.body as BatchNodeVMExtensionListResultOutput;
expect(body?.value?.length).toEqual(1);
expect(body?.value?.[0]?.vmExtension?.name).toEqual("extension-name");
expect(body?.value?.[0]?.vmExtension?.type).toEqual("extension-type");
expect(body?.value?.[0]?.vmExtension?.publisher).toEqual(
"extension-publisher"
);
expect(body?.value?.[0]?.vmExtension?.typeHandlerVersion).toEqual(
"1.0"
);
expect(body?.value?.[0]?.provisioningState).toEqual("success");
});
});

Просмотреть файл

@ -0,0 +1,28 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
*/
import { TokenCredential } from "@azure/core-auth";
import { ClientOptions } from "@azure-rest/core-client";
import { BatchClient } from "./generated/src";
import createClient from "./generated/src/batchClient";
import { BatchHttpClient } from "../client-http/batch-http-client";
export function createBatchClient(
endpoint: string,
options: ClientOptions = {},
credential?: TokenCredential
): BatchClient {
if (!options.httpClient) {
options = {
...options,
httpClient: new BatchHttpClient(),
apiVersion: "2023-05-01.17.0",
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const credentials = credential ?? (undefined as any);
return createClient(endpoint, credentials, options);
}

Просмотреть файл

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { getClient, ClientOptions } from "@azure-rest/core-client";
import { logger } from "./logger";
import { TokenCredential } from "@azure/core-auth";
import { BatchClient } from "./clientDefinitions";
/**
* Initialize a new instance of `BatchClient`
* @param endpoint - Batch account endpoint (for example: https://batchaccount.eastus2.batch.azure.com).
* @param credentials - uniquely identify client credential
* @param options - the parameter for all optional parameters
*/
export default function createClient(
endpoint: string,
credentials: TokenCredential,
options: ClientOptions = {}
): BatchClient {
const baseUrl = options.baseUrl ?? `${endpoint}`;
options.apiVersion = options.apiVersion ?? "2023-11-01.18.0";
const userAgentInfo = `azsdk-js-batch-rest/1.0.0-beta.1`;
const userAgentPrefix =
options.userAgentOptions && options.userAgentOptions.userAgentPrefix
? `${options.userAgentOptions.userAgentPrefix} ${userAgentInfo}`
: `${userAgentInfo}`;
options = {
...options,
userAgentOptions: {
userAgentPrefix,
},
loggingOptions: {
logger: options.loggingOptions?.logger ?? logger.info,
},
telemetryOptions: {
clientRequestIdHeaderName:
options.telemetryOptions?.clientRequestIdHeaderName ??
"client-request-id",
},
credentials: {
scopes: options.credentials?.scopes ?? [
"https://batch.core.windows.net//.default",
],
},
};
const client = getClient(baseUrl, credentials, options) as BatchClient;
return client;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import BatchClient from "./batchClient";
export * from "./batchClient";
export * from "./parameters";
export * from "./responses";
export * from "./clientDefinitions";
export * from "./isUnexpected";
export * from "./models";
export * from "./outputModels";
export * from "./paginateHelper";
export default BatchClient;

Просмотреть файл

@ -0,0 +1,821 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import {
ListApplications200Response,
ListApplicationsDefaultResponse,
GetApplication200Response,
GetApplicationDefaultResponse,
ListPoolUsageMetrics200Response,
ListPoolUsageMetricsDefaultResponse,
CreatePool201Response,
CreatePoolDefaultResponse,
ListPools200Response,
ListPoolsDefaultResponse,
DeletePool202Response,
DeletePoolDefaultResponse,
PoolExists200Response,
PoolExists404Response,
PoolExistsDefaultResponse,
GetPool200Response,
GetPoolDefaultResponse,
UpdatePool200Response,
UpdatePoolDefaultResponse,
DisablePoolAutoScale200Response,
DisablePoolAutoScaleDefaultResponse,
EnablePoolAutoScale200Response,
EnablePoolAutoScaleDefaultResponse,
EvaluatePoolAutoScale200Response,
EvaluatePoolAutoScaleDefaultResponse,
ResizePool202Response,
ResizePoolDefaultResponse,
StopPoolResize202Response,
StopPoolResizeDefaultResponse,
ReplacePoolProperties204Response,
ReplacePoolPropertiesDefaultResponse,
RemoveNodes202Response,
RemoveNodesDefaultResponse,
ListSupportedImages200Response,
ListSupportedImagesDefaultResponse,
ListPoolNodeCounts200Response,
ListPoolNodeCountsDefaultResponse,
DeleteJob202Response,
DeleteJobDefaultResponse,
GetJob200Response,
GetJobDefaultResponse,
UpdateJob200Response,
UpdateJobDefaultResponse,
ReplaceJob200Response,
ReplaceJobDefaultResponse,
DisableJob202Response,
DisableJobDefaultResponse,
EnableJob202Response,
EnableJobDefaultResponse,
TerminateJob202Response,
TerminateJobDefaultResponse,
CreateJob201Response,
CreateJobDefaultResponse,
ListJobs200Response,
ListJobsDefaultResponse,
ListJobsFromSchedule200Response,
ListJobsFromScheduleDefaultResponse,
ListJobPreparationAndReleaseTaskStatus200Response,
ListJobPreparationAndReleaseTaskStatusDefaultResponse,
GetJobTaskCounts200Response,
GetJobTaskCountsDefaultResponse,
CreateCertificate201Response,
CreateCertificateDefaultResponse,
ListCertificates200Response,
ListCertificatesDefaultResponse,
CancelCertificateDeletion204Response,
CancelCertificateDeletionDefaultResponse,
DeleteCertificate202Response,
DeleteCertificateDefaultResponse,
GetCertificate200Response,
GetCertificateDefaultResponse,
JobScheduleExists200Response,
JobScheduleExists404Response,
JobScheduleExistsDefaultResponse,
DeleteJobSchedule202Response,
DeleteJobScheduleDefaultResponse,
GetJobSchedule200Response,
GetJobScheduleDefaultResponse,
UpdateJobSchedule200Response,
UpdateJobScheduleDefaultResponse,
ReplaceJobSchedule200Response,
ReplaceJobScheduleDefaultResponse,
DisableJobSchedule204Response,
DisableJobScheduleDefaultResponse,
EnableJobSchedule204Response,
EnableJobScheduleDefaultResponse,
TerminateJobSchedule202Response,
TerminateJobScheduleDefaultResponse,
CreateJobSchedule201Response,
CreateJobScheduleDefaultResponse,
ListJobSchedules200Response,
ListJobSchedulesDefaultResponse,
CreateTask201Response,
CreateTaskDefaultResponse,
ListTasks200Response,
ListTasksDefaultResponse,
CreateTaskCollection200Response,
CreateTaskCollectionDefaultResponse,
DeleteTask200Response,
DeleteTaskDefaultResponse,
GetTask200Response,
GetTaskDefaultResponse,
ReplaceTask200Response,
ReplaceTaskDefaultResponse,
ListSubTasks200Response,
ListSubTasksDefaultResponse,
TerminateTask204Response,
TerminateTaskDefaultResponse,
ReactivateTask204Response,
ReactivateTaskDefaultResponse,
DeleteTaskFile200Response,
DeleteTaskFileDefaultResponse,
GetTaskFile200Response,
GetTaskFileDefaultResponse,
GetTaskFileProperties200Response,
GetTaskFilePropertiesDefaultResponse,
ListTaskFiles200Response,
ListTaskFilesDefaultResponse,
CreateNodeUser201Response,
CreateNodeUserDefaultResponse,
DeleteNodeUser200Response,
DeleteNodeUserDefaultResponse,
ReplaceNodeUser200Response,
ReplaceNodeUserDefaultResponse,
GetNode200Response,
GetNodeDefaultResponse,
RebootNode202Response,
RebootNodeDefaultResponse,
ReimageNode202Response,
ReimageNodeDefaultResponse,
DisableNodeScheduling200Response,
DisableNodeSchedulingDefaultResponse,
EnableNodeScheduling200Response,
EnableNodeSchedulingDefaultResponse,
GetNodeRemoteLoginSettings200Response,
GetNodeRemoteLoginSettingsDefaultResponse,
GetNodeRemoteDesktopFile200Response,
GetNodeRemoteDesktopFileDefaultResponse,
UploadNodeLogs200Response,
UploadNodeLogsDefaultResponse,
ListNodes200Response,
ListNodesDefaultResponse,
GetNodeExtension200Response,
GetNodeExtensionDefaultResponse,
ListNodeExtensions200Response,
ListNodeExtensionsDefaultResponse,
DeleteNodeFile200Response,
DeleteNodeFileDefaultResponse,
GetNodeFile200Response,
GetNodeFileDefaultResponse,
GetNodeFileProperties200Response,
GetNodeFilePropertiesDefaultResponse,
ListNodeFiles200Response,
ListNodeFilesDefaultResponse,
} from "./responses";
const responseMap: Record<string, string[]> = {
"GET /applications": ["200"],
"GET /applications/{applicationId}": ["200"],
"GET /poolusagemetrics": ["200"],
"POST /pools": ["201"],
"GET /pools": ["200"],
"DELETE /pools/{poolId}": ["202"],
"HEAD /pools/{poolId}": ["200", "404"],
"GET /pools/{poolId}": ["200"],
"PATCH /pools/{poolId}": ["200"],
"POST /pools/{poolId}/disableautoscale": ["200"],
"POST /pools/{poolId}/enableautoscale": ["200"],
"POST /pools/{poolId}/evaluateautoscale": ["200"],
"POST /pools/{poolId}/resize": ["202"],
"POST /pools/{poolId}/stopresize": ["202"],
"POST /pools/{poolId}/updateproperties": ["204"],
"POST /pools/{poolId}/removenodes": ["202"],
"GET /supportedimages": ["200"],
"GET /nodecounts": ["200"],
"DELETE /jobs/{jobId}": ["202"],
"GET /jobs/{jobId}": ["200"],
"PATCH /jobs/{jobId}": ["200"],
"PUT /jobs/{jobId}": ["200"],
"POST /jobs/{jobId}/disable": ["202"],
"POST /jobs/{jobId}/enable": ["202"],
"POST /jobs/{jobId}/terminate": ["202"],
"POST /jobs": ["201"],
"GET /jobs": ["200"],
"GET /jobschedules/{jobScheduleId}/jobs": ["200"],
"GET /jobs/{jobId}/jobpreparationandreleasetaskstatus": ["200"],
"GET /jobs/{jobId}/taskcounts": ["200"],
"POST /certificates": ["201"],
"GET /certificates": ["200"],
"POST /certificates(thumbprintAlgorithm={thumbprintAlgorithm},thumbprint={thumbprint})/canceldelete":
["204"],
"DELETE /certificates(thumbprintAlgorithm={thumbprintAlgorithm},thumbprint={thumbprint})":
["202"],
"GET /certificates(thumbprintAlgorithm={thumbprintAlgorithm},thumbprint={thumbprint})":
["200"],
"HEAD /jobschedules/{jobScheduleId}": ["200", "404"],
"DELETE /jobschedules/{jobScheduleId}": ["202"],
"GET /jobschedules/{jobScheduleId}": ["200"],
"PATCH /jobschedules/{jobScheduleId}": ["200"],
"PUT /jobschedules/{jobScheduleId}": ["200"],
"POST /jobschedules/{jobScheduleId}/disable": ["204"],
"POST /jobschedules/{jobScheduleId}/enable": ["204"],
"POST /jobschedules/{jobScheduleId}/terminate": ["202"],
"POST /jobschedules": ["201"],
"GET /jobschedules": ["200"],
"POST /jobs/{jobId}/tasks": ["201"],
"GET /jobs/{jobId}/tasks": ["200"],
"POST /jobs/{jobId}/addtaskcollection": ["200"],
"DELETE /jobs/{jobId}/tasks/{taskId}": ["200"],
"GET /jobs/{jobId}/tasks/{taskId}": ["200"],
"PUT /jobs/{jobId}/tasks/{taskId}": ["200"],
"GET /jobs/{jobId}/tasks/{taskId}/subtasksinfo": ["200"],
"POST /jobs/{jobId}/tasks/{taskId}/terminate": ["204"],
"POST /jobs/{jobId}/tasks/{taskId}/reactivate": ["204"],
"DELETE /jobs/{jobId}/tasks/{taskId}/files/{filePath}": ["200"],
"GET /jobs/{jobId}/tasks/{taskId}/files/{filePath}": ["200"],
"HEAD /jobs/{jobId}/tasks/{taskId}/files/{filePath}": ["200"],
"GET /jobs/{jobId}/tasks/{taskId}/files": ["200"],
"POST /pools/{poolId}/nodes/{nodeId}/users": ["201"],
"DELETE /pools/{poolId}/nodes/{nodeId}/users/{userName}": ["200"],
"PUT /pools/{poolId}/nodes/{nodeId}/users/{userName}": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}": ["200"],
"POST /pools/{poolId}/nodes/{nodeId}/reboot": ["202"],
"POST /pools/{poolId}/nodes/{nodeId}/reimage": ["202"],
"POST /pools/{poolId}/nodes/{nodeId}/disablescheduling": ["200"],
"POST /pools/{poolId}/nodes/{nodeId}/enablescheduling": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/remoteloginsettings": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/rdp": ["200"],
"POST /pools/{poolId}/nodes/{nodeId}/uploadbatchservicelogs": ["200"],
"GET /pools/{poolId}/nodes": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/extensions/{extensionName}": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/extensions": ["200"],
"DELETE /pools/{poolId}/nodes/{nodeId}/files/{filePath}": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/files/{filePath}": ["200"],
"HEAD /pools/{poolId}/nodes/{nodeId}/files/{filePath}": ["200"],
"GET /pools/{poolId}/nodes/{nodeId}/files": ["200"],
};
export function isUnexpected(
response: ListApplications200Response | ListApplicationsDefaultResponse
): response is ListApplicationsDefaultResponse;
export function isUnexpected(
response: GetApplication200Response | GetApplicationDefaultResponse
): response is GetApplicationDefaultResponse;
export function isUnexpected(
response:
| ListPoolUsageMetrics200Response
| ListPoolUsageMetricsDefaultResponse
): response is ListPoolUsageMetricsDefaultResponse;
export function isUnexpected(
response: CreatePool201Response | CreatePoolDefaultResponse
): response is CreatePoolDefaultResponse;
export function isUnexpected(
response: ListPools200Response | ListPoolsDefaultResponse
): response is ListPoolsDefaultResponse;
export function isUnexpected(
response: DeletePool202Response | DeletePoolDefaultResponse
): response is DeletePoolDefaultResponse;
export function isUnexpected(
response:
| PoolExists200Response
| PoolExists404Response
| PoolExistsDefaultResponse
): response is PoolExistsDefaultResponse;
export function isUnexpected(
response: GetPool200Response | GetPoolDefaultResponse
): response is GetPoolDefaultResponse;
export function isUnexpected(
response: UpdatePool200Response | UpdatePoolDefaultResponse
): response is UpdatePoolDefaultResponse;
export function isUnexpected(
response:
| DisablePoolAutoScale200Response
| DisablePoolAutoScaleDefaultResponse
): response is DisablePoolAutoScaleDefaultResponse;
export function isUnexpected(
response: EnablePoolAutoScale200Response | EnablePoolAutoScaleDefaultResponse
): response is EnablePoolAutoScaleDefaultResponse;
export function isUnexpected(
response:
| EvaluatePoolAutoScale200Response
| EvaluatePoolAutoScaleDefaultResponse
): response is EvaluatePoolAutoScaleDefaultResponse;
export function isUnexpected(
response: ResizePool202Response | ResizePoolDefaultResponse
): response is ResizePoolDefaultResponse;
export function isUnexpected(
response: StopPoolResize202Response | StopPoolResizeDefaultResponse
): response is StopPoolResizeDefaultResponse;
export function isUnexpected(
response:
| ReplacePoolProperties204Response
| ReplacePoolPropertiesDefaultResponse
): response is ReplacePoolPropertiesDefaultResponse;
export function isUnexpected(
response: RemoveNodes202Response | RemoveNodesDefaultResponse
): response is RemoveNodesDefaultResponse;
export function isUnexpected(
response: ListSupportedImages200Response | ListSupportedImagesDefaultResponse
): response is ListSupportedImagesDefaultResponse;
export function isUnexpected(
response: ListPoolNodeCounts200Response | ListPoolNodeCountsDefaultResponse
): response is ListPoolNodeCountsDefaultResponse;
export function isUnexpected(
response: DeleteJob202Response | DeleteJobDefaultResponse
): response is DeleteJobDefaultResponse;
export function isUnexpected(
response: GetJob200Response | GetJobDefaultResponse
): response is GetJobDefaultResponse;
export function isUnexpected(
response: UpdateJob200Response | UpdateJobDefaultResponse
): response is UpdateJobDefaultResponse;
export function isUnexpected(
response: ReplaceJob200Response | ReplaceJobDefaultResponse
): response is ReplaceJobDefaultResponse;
export function isUnexpected(
response: DisableJob202Response | DisableJobDefaultResponse
): response is DisableJobDefaultResponse;
export function isUnexpected(
response: EnableJob202Response | EnableJobDefaultResponse
): response is EnableJobDefaultResponse;
export function isUnexpected(
response: TerminateJob202Response | TerminateJobDefaultResponse
): response is TerminateJobDefaultResponse;
export function isUnexpected(
response: CreateJob201Response | CreateJobDefaultResponse
): response is CreateJobDefaultResponse;
export function isUnexpected(
response: ListJobs200Response | ListJobsDefaultResponse
): response is ListJobsDefaultResponse;
export function isUnexpected(
response:
| ListJobsFromSchedule200Response
| ListJobsFromScheduleDefaultResponse
): response is ListJobsFromScheduleDefaultResponse;
export function isUnexpected(
response:
| ListJobPreparationAndReleaseTaskStatus200Response
| ListJobPreparationAndReleaseTaskStatusDefaultResponse
): response is ListJobPreparationAndReleaseTaskStatusDefaultResponse;
export function isUnexpected(
response: GetJobTaskCounts200Response | GetJobTaskCountsDefaultResponse
): response is GetJobTaskCountsDefaultResponse;
export function isUnexpected(
response: CreateCertificate201Response | CreateCertificateDefaultResponse
): response is CreateCertificateDefaultResponse;
export function isUnexpected(
response: ListCertificates200Response | ListCertificatesDefaultResponse
): response is ListCertificatesDefaultResponse;
export function isUnexpected(
response:
| CancelCertificateDeletion204Response
| CancelCertificateDeletionDefaultResponse
): response is CancelCertificateDeletionDefaultResponse;
export function isUnexpected(
response: DeleteCertificate202Response | DeleteCertificateDefaultResponse
): response is DeleteCertificateDefaultResponse;
export function isUnexpected(
response: GetCertificate200Response | GetCertificateDefaultResponse
): response is GetCertificateDefaultResponse;
export function isUnexpected(
response:
| JobScheduleExists200Response
| JobScheduleExists404Response
| JobScheduleExistsDefaultResponse
): response is JobScheduleExistsDefaultResponse;
export function isUnexpected(
response: DeleteJobSchedule202Response | DeleteJobScheduleDefaultResponse
): response is DeleteJobScheduleDefaultResponse;
export function isUnexpected(
response: GetJobSchedule200Response | GetJobScheduleDefaultResponse
): response is GetJobScheduleDefaultResponse;
export function isUnexpected(
response: UpdateJobSchedule200Response | UpdateJobScheduleDefaultResponse
): response is UpdateJobScheduleDefaultResponse;
export function isUnexpected(
response: ReplaceJobSchedule200Response | ReplaceJobScheduleDefaultResponse
): response is ReplaceJobScheduleDefaultResponse;
export function isUnexpected(
response: DisableJobSchedule204Response | DisableJobScheduleDefaultResponse
): response is DisableJobScheduleDefaultResponse;
export function isUnexpected(
response: EnableJobSchedule204Response | EnableJobScheduleDefaultResponse
): response is EnableJobScheduleDefaultResponse;
export function isUnexpected(
response:
| TerminateJobSchedule202Response
| TerminateJobScheduleDefaultResponse
): response is TerminateJobScheduleDefaultResponse;
export function isUnexpected(
response: CreateJobSchedule201Response | CreateJobScheduleDefaultResponse
): response is CreateJobScheduleDefaultResponse;
export function isUnexpected(
response: ListJobSchedules200Response | ListJobSchedulesDefaultResponse
): response is ListJobSchedulesDefaultResponse;
export function isUnexpected(
response: CreateTask201Response | CreateTaskDefaultResponse
): response is CreateTaskDefaultResponse;
export function isUnexpected(
response: ListTasks200Response | ListTasksDefaultResponse
): response is ListTasksDefaultResponse;
export function isUnexpected(
response:
| CreateTaskCollection200Response
| CreateTaskCollectionDefaultResponse
): response is CreateTaskCollectionDefaultResponse;
export function isUnexpected(
response: DeleteTask200Response | DeleteTaskDefaultResponse
): response is DeleteTaskDefaultResponse;
export function isUnexpected(
response: GetTask200Response | GetTaskDefaultResponse
): response is GetTaskDefaultResponse;
export function isUnexpected(
response: ReplaceTask200Response | ReplaceTaskDefaultResponse
): response is ReplaceTaskDefaultResponse;
export function isUnexpected(
response: ListSubTasks200Response | ListSubTasksDefaultResponse
): response is ListSubTasksDefaultResponse;
export function isUnexpected(
response: TerminateTask204Response | TerminateTaskDefaultResponse
): response is TerminateTaskDefaultResponse;
export function isUnexpected(
response: ReactivateTask204Response | ReactivateTaskDefaultResponse
): response is ReactivateTaskDefaultResponse;
export function isUnexpected(
response: DeleteTaskFile200Response | DeleteTaskFileDefaultResponse
): response is DeleteTaskFileDefaultResponse;
export function isUnexpected(
response: GetTaskFile200Response | GetTaskFileDefaultResponse
): response is GetTaskFileDefaultResponse;
export function isUnexpected(
response:
| GetTaskFileProperties200Response
| GetTaskFilePropertiesDefaultResponse
): response is GetTaskFilePropertiesDefaultResponse;
export function isUnexpected(
response: ListTaskFiles200Response | ListTaskFilesDefaultResponse
): response is ListTaskFilesDefaultResponse;
export function isUnexpected(
response: CreateNodeUser201Response | CreateNodeUserDefaultResponse
): response is CreateNodeUserDefaultResponse;
export function isUnexpected(
response: DeleteNodeUser200Response | DeleteNodeUserDefaultResponse
): response is DeleteNodeUserDefaultResponse;
export function isUnexpected(
response: ReplaceNodeUser200Response | ReplaceNodeUserDefaultResponse
): response is ReplaceNodeUserDefaultResponse;
export function isUnexpected(
response: GetNode200Response | GetNodeDefaultResponse
): response is GetNodeDefaultResponse;
export function isUnexpected(
response: RebootNode202Response | RebootNodeDefaultResponse
): response is RebootNodeDefaultResponse;
export function isUnexpected(
response: ReimageNode202Response | ReimageNodeDefaultResponse
): response is ReimageNodeDefaultResponse;
export function isUnexpected(
response:
| DisableNodeScheduling200Response
| DisableNodeSchedulingDefaultResponse
): response is DisableNodeSchedulingDefaultResponse;
export function isUnexpected(
response:
| EnableNodeScheduling200Response
| EnableNodeSchedulingDefaultResponse
): response is EnableNodeSchedulingDefaultResponse;
export function isUnexpected(
response:
| GetNodeRemoteLoginSettings200Response
| GetNodeRemoteLoginSettingsDefaultResponse
): response is GetNodeRemoteLoginSettingsDefaultResponse;
export function isUnexpected(
response:
| GetNodeRemoteDesktopFile200Response
| GetNodeRemoteDesktopFileDefaultResponse
): response is GetNodeRemoteDesktopFileDefaultResponse;
export function isUnexpected(
response: UploadNodeLogs200Response | UploadNodeLogsDefaultResponse
): response is UploadNodeLogsDefaultResponse;
export function isUnexpected(
response: ListNodes200Response | ListNodesDefaultResponse
): response is ListNodesDefaultResponse;
export function isUnexpected(
response: GetNodeExtension200Response | GetNodeExtensionDefaultResponse
): response is GetNodeExtensionDefaultResponse;
export function isUnexpected(
response: ListNodeExtensions200Response | ListNodeExtensionsDefaultResponse
): response is ListNodeExtensionsDefaultResponse;
export function isUnexpected(
response: DeleteNodeFile200Response | DeleteNodeFileDefaultResponse
): response is DeleteNodeFileDefaultResponse;
export function isUnexpected(
response: GetNodeFile200Response | GetNodeFileDefaultResponse
): response is GetNodeFileDefaultResponse;
export function isUnexpected(
response:
| GetNodeFileProperties200Response
| GetNodeFilePropertiesDefaultResponse
): response is GetNodeFilePropertiesDefaultResponse;
export function isUnexpected(
response: ListNodeFiles200Response | ListNodeFilesDefaultResponse
): response is ListNodeFilesDefaultResponse;
export function isUnexpected(
response:
| ListApplications200Response
| ListApplicationsDefaultResponse
| GetApplication200Response
| GetApplicationDefaultResponse
| ListPoolUsageMetrics200Response
| ListPoolUsageMetricsDefaultResponse
| CreatePool201Response
| CreatePoolDefaultResponse
| ListPools200Response
| ListPoolsDefaultResponse
| DeletePool202Response
| DeletePoolDefaultResponse
| PoolExists200Response
| PoolExists404Response
| PoolExistsDefaultResponse
| GetPool200Response
| GetPoolDefaultResponse
| UpdatePool200Response
| UpdatePoolDefaultResponse
| DisablePoolAutoScale200Response
| DisablePoolAutoScaleDefaultResponse
| EnablePoolAutoScale200Response
| EnablePoolAutoScaleDefaultResponse
| EvaluatePoolAutoScale200Response
| EvaluatePoolAutoScaleDefaultResponse
| ResizePool202Response
| ResizePoolDefaultResponse
| StopPoolResize202Response
| StopPoolResizeDefaultResponse
| ReplacePoolProperties204Response
| ReplacePoolPropertiesDefaultResponse
| RemoveNodes202Response
| RemoveNodesDefaultResponse
| ListSupportedImages200Response
| ListSupportedImagesDefaultResponse
| ListPoolNodeCounts200Response
| ListPoolNodeCountsDefaultResponse
| DeleteJob202Response
| DeleteJobDefaultResponse
| GetJob200Response
| GetJobDefaultResponse
| UpdateJob200Response
| UpdateJobDefaultResponse
| ReplaceJob200Response
| ReplaceJobDefaultResponse
| DisableJob202Response
| DisableJobDefaultResponse
| EnableJob202Response
| EnableJobDefaultResponse
| TerminateJob202Response
| TerminateJobDefaultResponse
| CreateJob201Response
| CreateJobDefaultResponse
| ListJobs200Response
| ListJobsDefaultResponse
| ListJobsFromSchedule200Response
| ListJobsFromScheduleDefaultResponse
| ListJobPreparationAndReleaseTaskStatus200Response
| ListJobPreparationAndReleaseTaskStatusDefaultResponse
| GetJobTaskCounts200Response
| GetJobTaskCountsDefaultResponse
| CreateCertificate201Response
| CreateCertificateDefaultResponse
| ListCertificates200Response
| ListCertificatesDefaultResponse
| CancelCertificateDeletion204Response
| CancelCertificateDeletionDefaultResponse
| DeleteCertificate202Response
| DeleteCertificateDefaultResponse
| GetCertificate200Response
| GetCertificateDefaultResponse
| JobScheduleExists200Response
| JobScheduleExists404Response
| JobScheduleExistsDefaultResponse
| DeleteJobSchedule202Response
| DeleteJobScheduleDefaultResponse
| GetJobSchedule200Response
| GetJobScheduleDefaultResponse
| UpdateJobSchedule200Response
| UpdateJobScheduleDefaultResponse
| ReplaceJobSchedule200Response
| ReplaceJobScheduleDefaultResponse
| DisableJobSchedule204Response
| DisableJobScheduleDefaultResponse
| EnableJobSchedule204Response
| EnableJobScheduleDefaultResponse
| TerminateJobSchedule202Response
| TerminateJobScheduleDefaultResponse
| CreateJobSchedule201Response
| CreateJobScheduleDefaultResponse
| ListJobSchedules200Response
| ListJobSchedulesDefaultResponse
| CreateTask201Response
| CreateTaskDefaultResponse
| ListTasks200Response
| ListTasksDefaultResponse
| CreateTaskCollection200Response
| CreateTaskCollectionDefaultResponse
| DeleteTask200Response
| DeleteTaskDefaultResponse
| GetTask200Response
| GetTaskDefaultResponse
| ReplaceTask200Response
| ReplaceTaskDefaultResponse
| ListSubTasks200Response
| ListSubTasksDefaultResponse
| TerminateTask204Response
| TerminateTaskDefaultResponse
| ReactivateTask204Response
| ReactivateTaskDefaultResponse
| DeleteTaskFile200Response
| DeleteTaskFileDefaultResponse
| GetTaskFile200Response
| GetTaskFileDefaultResponse
| GetTaskFileProperties200Response
| GetTaskFilePropertiesDefaultResponse
| ListTaskFiles200Response
| ListTaskFilesDefaultResponse
| CreateNodeUser201Response
| CreateNodeUserDefaultResponse
| DeleteNodeUser200Response
| DeleteNodeUserDefaultResponse
| ReplaceNodeUser200Response
| ReplaceNodeUserDefaultResponse
| GetNode200Response
| GetNodeDefaultResponse
| RebootNode202Response
| RebootNodeDefaultResponse
| ReimageNode202Response
| ReimageNodeDefaultResponse
| DisableNodeScheduling200Response
| DisableNodeSchedulingDefaultResponse
| EnableNodeScheduling200Response
| EnableNodeSchedulingDefaultResponse
| GetNodeRemoteLoginSettings200Response
| GetNodeRemoteLoginSettingsDefaultResponse
| GetNodeRemoteDesktopFile200Response
| GetNodeRemoteDesktopFileDefaultResponse
| UploadNodeLogs200Response
| UploadNodeLogsDefaultResponse
| ListNodes200Response
| ListNodesDefaultResponse
| GetNodeExtension200Response
| GetNodeExtensionDefaultResponse
| ListNodeExtensions200Response
| ListNodeExtensionsDefaultResponse
| DeleteNodeFile200Response
| DeleteNodeFileDefaultResponse
| GetNodeFile200Response
| GetNodeFileDefaultResponse
| GetNodeFileProperties200Response
| GetNodeFilePropertiesDefaultResponse
| ListNodeFiles200Response
| ListNodeFilesDefaultResponse
): response is
| ListApplicationsDefaultResponse
| GetApplicationDefaultResponse
| ListPoolUsageMetricsDefaultResponse
| CreatePoolDefaultResponse
| ListPoolsDefaultResponse
| DeletePoolDefaultResponse
| PoolExistsDefaultResponse
| GetPoolDefaultResponse
| UpdatePoolDefaultResponse
| DisablePoolAutoScaleDefaultResponse
| EnablePoolAutoScaleDefaultResponse
| EvaluatePoolAutoScaleDefaultResponse
| ResizePoolDefaultResponse
| StopPoolResizeDefaultResponse
| ReplacePoolPropertiesDefaultResponse
| RemoveNodesDefaultResponse
| ListSupportedImagesDefaultResponse
| ListPoolNodeCountsDefaultResponse
| DeleteJobDefaultResponse
| GetJobDefaultResponse
| UpdateJobDefaultResponse
| ReplaceJobDefaultResponse
| DisableJobDefaultResponse
| EnableJobDefaultResponse
| TerminateJobDefaultResponse
| CreateJobDefaultResponse
| ListJobsDefaultResponse
| ListJobsFromScheduleDefaultResponse
| ListJobPreparationAndReleaseTaskStatusDefaultResponse
| GetJobTaskCountsDefaultResponse
| CreateCertificateDefaultResponse
| ListCertificatesDefaultResponse
| CancelCertificateDeletionDefaultResponse
| DeleteCertificateDefaultResponse
| GetCertificateDefaultResponse
| JobScheduleExistsDefaultResponse
| DeleteJobScheduleDefaultResponse
| GetJobScheduleDefaultResponse
| UpdateJobScheduleDefaultResponse
| ReplaceJobScheduleDefaultResponse
| DisableJobScheduleDefaultResponse
| EnableJobScheduleDefaultResponse
| TerminateJobScheduleDefaultResponse
| CreateJobScheduleDefaultResponse
| ListJobSchedulesDefaultResponse
| CreateTaskDefaultResponse
| ListTasksDefaultResponse
| CreateTaskCollectionDefaultResponse
| DeleteTaskDefaultResponse
| GetTaskDefaultResponse
| ReplaceTaskDefaultResponse
| ListSubTasksDefaultResponse
| TerminateTaskDefaultResponse
| ReactivateTaskDefaultResponse
| DeleteTaskFileDefaultResponse
| GetTaskFileDefaultResponse
| GetTaskFilePropertiesDefaultResponse
| ListTaskFilesDefaultResponse
| CreateNodeUserDefaultResponse
| DeleteNodeUserDefaultResponse
| ReplaceNodeUserDefaultResponse
| GetNodeDefaultResponse
| RebootNodeDefaultResponse
| ReimageNodeDefaultResponse
| DisableNodeSchedulingDefaultResponse
| EnableNodeSchedulingDefaultResponse
| GetNodeRemoteLoginSettingsDefaultResponse
| GetNodeRemoteDesktopFileDefaultResponse
| UploadNodeLogsDefaultResponse
| ListNodesDefaultResponse
| GetNodeExtensionDefaultResponse
| ListNodeExtensionsDefaultResponse
| DeleteNodeFileDefaultResponse
| GetNodeFileDefaultResponse
| GetNodeFilePropertiesDefaultResponse
| ListNodeFilesDefaultResponse {
const lroOriginal = response.headers["x-ms-original-url"];
const url = new URL(lroOriginal ?? response.request.url);
const method = response.request.method;
let pathDetails = responseMap[`${method} ${url.pathname}`];
if (!pathDetails) {
pathDetails = getParametrizedPathSuccess(method, url.pathname);
}
return !pathDetails.includes(response.status);
}
function getParametrizedPathSuccess(method: string, path: string): string[] {
const pathParts = path.split("/");
// Traverse list to match the longest candidate
// matchedLen: the length of candidate path
// matchedValue: the matched status code array
let matchedLen = -1,
matchedValue: string[] = [];
// Iterate the responseMap to find a match
for (const [key, value] of Object.entries(responseMap)) {
// Extracting the path from the map key which is in format
// GET /path/foo
if (!key.startsWith(method)) {
continue;
}
const candidatePath = getPathFromMapKey(key);
// Get each part of the url path
const candidateParts = candidatePath.split("/");
// track if we have found a match to return the values found.
let found = true;
for (
let i = candidateParts.length - 1, j = pathParts.length - 1;
i >= 1 && j >= 1;
i--, j--
) {
if (
candidateParts[i]?.startsWith("{") &&
candidateParts[i]?.indexOf("}") !== -1
) {
const start = candidateParts[i]!.indexOf("}") + 1,
end = candidateParts[i]?.length;
// If the current part of the candidate is a "template" part
// Try to use the suffix of pattern to match the path
// {guid} ==> $
// {guid}:export ==> :export$
const isMatched = new RegExp(
`${candidateParts[i]?.slice(start, end)}`
).test(pathParts[j] || "");
if (!isMatched) {
found = false;
break;
}
continue;
}
// If the candidate part is not a template and
// the parts don't match mark the candidate as not found
// to move on with the next candidate path.
if (candidateParts[i] !== pathParts[j]) {
found = false;
break;
}
}
// We finished evaluating the current candidate parts
// Update the matched value if and only if we found the longer pattern
if (found && candidatePath.length > matchedLen) {
matchedLen = candidatePath.length;
matchedValue = value;
}
}
return matchedValue;
}
function getPathFromMapKey(mapKey: string): string {
const pathStart = mapKey.indexOf("/");
return mapKey.slice(pathStart);
}

Просмотреть файл

@ -0,0 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { createClientLogger } from "@azure/logger";
export const logger = createClientLogger("batch");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,200 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import {
getPagedAsyncIterator,
PagedAsyncIterableIterator,
PagedResult,
} from "@azure/core-paging";
import {
Client,
createRestError,
PathUncheckedResponse,
} from "@azure-rest/core-client";
/**
* Helper type to extract the type of an array
*/
export type GetArrayType<T> = T extends Array<infer TData> ? TData : never;
/**
* The type of a custom function that defines how to get a page and a link to the next one if any.
*/
export type GetPage<TPage> = (
pageLink: string,
maxPageSize?: number
) => Promise<{
page: TPage;
nextPageLink?: string;
}>;
/**
* Options for the paging helper
*/
export interface PagingOptions<TResponse> {
/**
* Custom function to extract pagination details for crating the PagedAsyncIterableIterator
*/
customGetPage?: GetPage<PaginateReturn<TResponse>[]>;
}
/**
* Helper type to infer the Type of the paged elements from the response type
* This type is generated based on the swagger information for x-ms-pageable
* specifically on the itemName property which indicates the property of the response
* where the page items are found. The default value is `value`.
* This type will allow us to provide strongly typed Iterator based on the response we get as second parameter
*/
export type PaginateReturn<TResult> = TResult extends {
body: { value?: infer TPage };
}
? GetArrayType<TPage>
: Array<unknown>;
/**
* Helper to paginate results from an initial response that follows the specification of Autorest `x-ms-pageable` extension
* @param client - Client to use for sending the next page requests
* @param initialResponse - Initial response containing the nextLink and current page of elements
* @param customGetPage - Optional - Function to define how to extract the page and next link to be used to paginate the results
* @returns - PagedAsyncIterableIterator to iterate the elements
*/
export function paginate<TResponse extends PathUncheckedResponse>(
client: Client,
initialResponse: TResponse,
options: PagingOptions<TResponse> = {}
): PagedAsyncIterableIterator<PaginateReturn<TResponse>> {
// Extract element type from initial response
type TElement = PaginateReturn<TResponse>;
let firstRun = true;
// We need to check the response for success before trying to inspect it looking for
// the properties to use for nextLink and itemName
checkPagingRequest(initialResponse);
const { itemName, nextLinkName } = getPaginationProperties(initialResponse);
const { customGetPage } = options;
const pagedResult: PagedResult<TElement[]> = {
firstPageLink: "",
getPage:
typeof customGetPage === "function"
? customGetPage
: async (pageLink: string) => {
const result = firstRun
? initialResponse
: await client.pathUnchecked(pageLink).get();
firstRun = false;
checkPagingRequest(result);
const nextLink = getNextLink(result.body, nextLinkName);
const values = getElements<TElement>(result.body, itemName);
return {
page: values,
nextPageLink: nextLink,
};
},
};
return getPagedAsyncIterator(pagedResult);
}
/**
* Gets for the value of nextLink in the body
*/
function getNextLink(body: unknown, nextLinkName?: string): string | undefined {
if (!nextLinkName) {
return undefined;
}
const nextLink = (body as Record<string, unknown>)[nextLinkName];
if (typeof nextLink !== "string" && typeof nextLink !== "undefined") {
throw new Error(
`Body Property ${nextLinkName} should be a string or undefined`
);
}
return nextLink;
}
/**
* Gets the elements of the current request in the body.
*/
function getElements<T = unknown>(body: unknown, itemName: string): T[] {
const value = (body as Record<string, unknown>)[itemName] as T[];
// value has to be an array according to the x-ms-pageable extension.
// The fact that this must be an array is used above to calculate the
// type of elements in the page in PaginateReturn
if (!Array.isArray(value)) {
throw new Error(
`Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}`
);
}
return value ?? [];
}
/**
* Checks if a request failed
*/
function checkPagingRequest(response: PathUncheckedResponse): void {
const Http2xxStatusCodes = [
"200",
"201",
"202",
"203",
"204",
"205",
"206",
"207",
"208",
"226",
];
if (!Http2xxStatusCodes.includes(response.status)) {
throw createRestError(
`Pagination failed with unexpected statusCode ${response.status}`,
response
);
}
}
/**
* Extracts the itemName and nextLinkName from the initial response to use them for pagination
*/
function getPaginationProperties(initialResponse: PathUncheckedResponse) {
// Build a set with the passed custom nextLinkNames
const nextLinkNames = new Set(["nextLink", "odata.nextLink"]);
// Build a set with the passed custom set of itemNames
const itemNames = new Set(["value"]);
let nextLinkName: string | undefined;
let itemName: string | undefined;
for (const name of nextLinkNames) {
const nextLink = (initialResponse.body as Record<string, unknown>)[
name
] as string;
if (nextLink) {
nextLinkName = name;
break;
}
}
for (const name of itemNames) {
const item = (initialResponse.body as Record<string, unknown>)[
name
] as string;
if (item) {
itemName = name;
break;
}
}
if (!itemName) {
throw new Error(
`Couldn't paginate response\n Body doesn't contain an array property with name: ${[
...itemNames,
].join(" OR ")}`
);
}
return { itemName, nextLinkName };
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,4 @@
directory: specification/batch/Azure.Batch
commit: e4b9c403b879114eabb38f23071161e5a6cd508e
repo: wiboris/azure-rest-api-specs
additionalDirectories:

Просмотреть файл

@ -0,0 +1,3 @@
/// <reference lib="esnext.asynciterable" />
export * from "./generated/src/index";
export * from "./client";

Просмотреть файл

@ -1,5 +1,5 @@
import { RawHttpHeaders } from "@azure/core-rest-pipeline";
import { PipelineHttpHeadersImpl } from "../http/pipeline-http-headers";
import { PipelineHttpHeadersImpl } from "../pipeline-http-headers";
import { MapHttpHeaders } from "@azure/bonito-core/lib/http";
describe("PipelineHttpHeadersImpl", () => {

Просмотреть файл

@ -0,0 +1,34 @@
import { initMockBatchEnvironment } from "../../environment";
import { BatchFakeSet, BasicBatchFakeSet } from "../../test-util/fakes";
import { FakeNodeService } from "../fake-node-service";
describe("FakeNodeService", () => {
const poolId = `/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo/pools/hobopool1`;
const nodeId = `tvmps_id1`;
let service: FakeNodeService;
let fakeSet: BatchFakeSet;
beforeEach(() => {
initMockBatchEnvironment();
fakeSet = new BasicBatchFakeSet();
service = new FakeNodeService();
service.setFakes(fakeSet);
});
test("List batch nodes", async () => {
const nodes = await service.listBatchNodes("", poolId);
expect(nodes?.map((node) => node.id)).toEqual([nodeId]);
});
test("List batch node extensions", async () => {
const extensions = await service.listBatchNodeExtensions(
"",
"",
nodeId
);
expect(
extensions?.map((extension) => extension?.vmExtension?.name)
).toEqual(["CustomExtension100"]);
});
});

Просмотреть файл

@ -0,0 +1,29 @@
import { OperationOptions } from "@azure/bonito-core";
import { BatchFakeSet, BasicBatchFakeSet } from "../test-util/fakes";
import { BatchNodeOutput, BatchNodeVMExtensionOutput } from "./node-models";
import type { NodeService } from "./node-service";
export class FakeNodeService implements NodeService {
fakeSet: BatchFakeSet = new BasicBatchFakeSet();
setFakes(fakeSet: BatchFakeSet): void {
this.fakeSet = fakeSet;
}
async listBatchNodes(
accountEndpoint: string,
poolId: string,
opts?: OperationOptions | undefined
): Promise<BatchNodeOutput[] | undefined> {
return this.fakeSet.listBatchNodes(poolId);
}
async listBatchNodeExtensions(
accountEndpoint: string,
poolId: string,
nodeId: string,
opts?: OperationOptions | undefined
): Promise<BatchNodeVMExtensionOutput[] | undefined> {
return this.fakeSet.listBatchNodeExtensions(nodeId);
}
}

Просмотреть файл

@ -0,0 +1,4 @@
export * from "./node-models";
export * from "./node-service";
export * from "./fake-node-service";
export * from "./live-node-service";

Просмотреть файл

@ -0,0 +1,58 @@
import { AbstractHttpService, OperationOptions } from "@azure/bonito-core";
import { BatchNodeOutput, BatchNodeVMExtensionOutput } from "./node-models";
import { NodeService } from "./node-service";
import { createBatchClient, isUnexpected } from "../internal/batch-rest";
import { createBatchUnexpectedStatusCodeError } from "../utils";
export class LiveNodeService
extends AbstractHttpService
implements NodeService
{
private _ensureHttpsEndpoint(accountEndpoint: string): string {
if (!accountEndpoint.startsWith("https://")) {
return `https://${accountEndpoint}`;
}
return accountEndpoint;
}
async listBatchNodes(
accountEndpoint: string,
poolId: string,
opts?: OperationOptions | undefined
): Promise<BatchNodeOutput[] | undefined> {
const listNodePath = "/pools/{poolId}/nodes";
const batchClient = createBatchClient(
this._ensureHttpsEndpoint(accountEndpoint)
);
const res = await batchClient.path(listNodePath, poolId).get();
if (isUnexpected(res)) {
throw createBatchUnexpectedStatusCodeError(res);
}
return res.body.value;
}
async listBatchNodeExtensions(
accountEndpoint: string,
poolId: string,
nodeId: string,
opts?: OperationOptions | undefined
): Promise<BatchNodeVMExtensionOutput[] | undefined> {
const listNodeExtensionPath =
"/pools/{poolId}/nodes/{nodeId}/extensions";
const batchClient = createBatchClient(
this._ensureHttpsEndpoint(accountEndpoint)
);
const res = await batchClient
.path(listNodeExtensionPath, poolId, nodeId)
.get();
if (isUnexpected(res)) {
throw createBatchUnexpectedStatusCodeError(res);
}
return res.body.value;
}
}

Просмотреть файл

@ -0,0 +1,4 @@
export {
BatchNodeVMExtensionOutput,
BatchNodeOutput,
} from "../internal/batch-rest";

Просмотреть файл

@ -0,0 +1,17 @@
import { OperationOptions } from "@azure/bonito-core";
import { BatchNodeOutput, BatchNodeVMExtensionOutput } from "./node-models";
export interface NodeService {
listBatchNodes(
accountEndpoint: string,
poolId: string,
opts?: OperationOptions
): Promise<BatchNodeOutput[] | undefined>;
listBatchNodeExtensions(
accountEndpoint: string,
poolId: string,
nodeId: string,
opts?: OperationOptions
): Promise<BatchNodeVMExtensionOutput[] | undefined>;
}

Просмотреть файл

@ -7,6 +7,9 @@ describe("FakePoolService", () => {
const hoboAcctId =
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo";
const hoboPoolArmId = `${hoboAcctId}/pools/hobopool1`;
const newTestPoolArmId = `${hoboAcctId}/pools/newtestpool`;
let service: FakePoolService;
let fakeSet: BatchFakeSet;
@ -23,9 +26,7 @@ describe("FakePoolService", () => {
});
test("Get by resource ID", async () => {
const pool = await service.get(
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo/pools/hobopool1"
);
const pool = await service.get(hoboPoolArmId);
expect(pool?.name).toEqual("hobopool1");
});
@ -57,7 +58,7 @@ describe("FakePoolService", () => {
},
};
const pool = await service.createOrUpdate(newPool);
const pool = await service.createOrUpdate(newTestPoolArmId, newPool);
expect(pool?.name).toEqual("newtestpool");
const pools = await service.listByAccountId(hoboAcctId);
@ -93,7 +94,7 @@ describe("FakePoolService", () => {
},
};
const pool = await service.createOrUpdate(poolUpdate);
const pool = await service.createOrUpdate(hoboPoolArmId, poolUpdate);
expect(pool?.name).toEqual("hobopool1");
// Updated an existing pool rather than created a new one
@ -116,7 +117,7 @@ describe("FakePoolService", () => {
},
};
const pool = await service.patch(update);
const pool = await service.patch(hoboPoolArmId, update);
expect(pool?.name).toEqual("hobopool1");
expect(
pool?.properties?.scaleSettings?.fixedScale?.targetDedicatedNodes

Просмотреть файл

@ -11,8 +11,8 @@ import { initMockBatchEnvironment } from "../../environment";
describe("LivePoolService", () => {
const hoboAcctId =
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo";
const hoboPoolOneId =
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo/pools/hobopool1";
const hoboPoolArmId = `${hoboAcctId}/pools/hobopool1`;
const newTestPoolArmId = `${hoboAcctId}/pools/newtestpool`;
let service: PoolService;
let fakeSet: BatchFakeSet;
@ -59,32 +59,35 @@ describe("LivePoolService", () => {
)
);
expect(() => service.listByAccountId(hoboAcctId)).rejects.toThrowError(
`Failed to list pools under account ${hoboAcctId} [unexpected 500 status]\nResponse body:\nBoom`
);
await expect(() => service.listByAccountId(hoboAcctId)).rejects
.toMatchInlineSnapshot(`
[Error: The Batch management plane returned an unexpected status code [unexpected 500 status]
Response body:
"Boom"]
`);
});
test("Get by resource ID", async () => {
httpClient.addExpected(
new MockHttpResponse(
`${getArmUrl()}${hoboPoolOneId}?api-version=${
`${getArmUrl()}${hoboPoolArmId}?api-version=${
BatchApiVersion.arm
}`,
{
status: 200,
body: JSON.stringify(fakeSet.getPool(hoboPoolOneId)),
body: JSON.stringify(fakeSet.getPool(hoboPoolArmId)),
}
)
);
const pool = await service.get(hoboPoolOneId);
const pool = await service.get(hoboPoolArmId);
expect(pool?.name).toEqual("hobopool1");
});
test("Get by resource ID error", async () => {
httpClient.addExpected(
new MockHttpResponse(
`${getArmUrl()}${hoboPoolOneId}?api-version=${
`${getArmUrl()}${hoboPoolArmId}?api-version=${
BatchApiVersion.arm
}`,
{
@ -94,9 +97,12 @@ describe("LivePoolService", () => {
)
);
expect(() => service.get(hoboPoolOneId)).rejects.toThrowError(
`Failed to get pool by ID ${hoboPoolOneId} [unexpected 500 status]\nResponse body:\nBoom`
);
await expect(() => service.get(hoboPoolArmId)).rejects
.toMatchInlineSnapshot(`
[Error: The Batch management plane returned an unexpected status code [unexpected 500 status]
Response body:
"Boom"]
`);
});
test("Create, update, patch", async () => {
@ -149,7 +155,7 @@ describe("LivePoolService", () => {
);
// Create
let pool = await service.createOrUpdate(newPool);
let pool = await service.createOrUpdate(newTestPoolArmId, newPool);
expect(pool?.name).toEqual("newtestpool");
if (newPool.properties?.scaleSettings?.fixedScale) {
@ -179,7 +185,7 @@ describe("LivePoolService", () => {
);
// Update
pool = await service.createOrUpdate(newPool);
pool = await service.createOrUpdate(newTestPoolArmId, newPool);
expect(pool?.name).toEqual("newtestpool");
const patch: Pool = {
@ -210,7 +216,7 @@ describe("LivePoolService", () => {
);
// Patch
pool = await service.patch(patch);
pool = await service.patch(newTestPoolArmId, patch);
expect(pool?.name).toEqual("newtestpool");
expect(
pool?.properties?.scaleSettings?.fixedScale?.targetDedicatedNodes

Просмотреть файл

@ -9,19 +9,19 @@ export class FakePoolService implements PoolService {
this.fakeSet = fakeSet;
}
async createOrUpdate(pool: Pool): Promise<PoolOutput> {
async createOrUpdate(poolArmId: string, pool: Pool): Promise<PoolOutput> {
return this.fakeSet.putPool(pool);
}
async get(id: string): Promise<PoolOutput | undefined> {
return this.fakeSet.getPool(id);
async get(poolArmId: string): Promise<PoolOutput | undefined> {
return this.fakeSet.getPool(poolArmId);
}
async listByAccountId(accountId: string): Promise<PoolOutput[]> {
return this.fakeSet.listPoolsByAccount(accountId);
}
async patch(pool: Pool): Promise<PoolOutput> {
async patch(poolArmId: string, pool: Pool): Promise<PoolOutput> {
return this.fakeSet.patchPool(pool);
}
}

Просмотреть файл

@ -1,119 +1,156 @@
import { BatchApiVersion } from "../constants";
import type { ListPoolsResultOutput, Pool, PoolOutput } from "./pool-models";
// import { BatchApiVersion } from "../constants";
import type { Pool, PoolOutput } from "./pool-models";
import type { PoolService } from "./pool-service";
import {
getHttpClient,
StandardHttpHeaders,
MediaType,
AbstractHttpService,
OperationOptions,
getArmUrl,
buildRequestMetadata,
UnexpectedStatusCodeError,
} from "@azure/bonito-core";
import { createARMBatchClient, isUnexpected } from "../internal/arm-batch-rest";
import {
createArmUnexpectedStatusCodeError,
parseBatchAccountIdInfo,
parsePoolArmIdInfo,
} from "../utils";
const SINGLE_POOL_PATH =
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}";
const POOLS_PATH =
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools";
export class LivePoolService
extends AbstractHttpService
implements PoolService
{
async createOrUpdate(
poolArmId: string,
pool: Pool,
opts?: OperationOptions
): Promise<PoolOutput> {
const response = await getHttpClient().put(
`${getArmUrl()}${pool.id}?api-version=${BatchApiVersion.arm}`,
{
body: JSON.stringify(pool),
metadata: buildRequestMetadata(opts),
}
);
const armBatchClient = createARMBatchClient({
baseUrl: getArmUrl(),
});
if (response.status === 200) {
return (await response.json()) as PoolOutput;
const {
subscriptionId,
resourceGroupName,
batchAccountName,
poolName,
} = parsePoolArmIdInfo(poolArmId);
const res = await armBatchClient
.path(
SINGLE_POOL_PATH,
subscriptionId,
resourceGroupName,
batchAccountName,
poolName
)
.put({
body: pool,
headers: {},
});
if (isUnexpected(res)) {
throw createArmUnexpectedStatusCodeError(res);
}
throw new UnexpectedStatusCodeError(
`Failed to create or update pool ${pool.id}`,
response.status,
await response.text()
);
return res.body;
}
async get(
id: string,
poolArmId: string,
opts?: OperationOptions
): Promise<PoolOutput | undefined> {
const response = await getHttpClient().get(
`${getArmUrl()}${id}?api-version=${BatchApiVersion.arm}`,
{
metadata: buildRequestMetadata(opts),
}
);
const armBatchClient = createARMBatchClient({
baseUrl: getArmUrl(),
});
if (response.status === 404) {
return undefined;
const {
subscriptionId,
resourceGroupName,
batchAccountName,
poolName,
} = parsePoolArmIdInfo(poolArmId);
const res = await armBatchClient
.path(
SINGLE_POOL_PATH,
subscriptionId,
resourceGroupName,
batchAccountName,
poolName
)
.get();
if (isUnexpected(res)) {
throw createArmUnexpectedStatusCodeError(res);
}
if (response.status === 200) {
return (await response.json()) as PoolOutput;
}
throw new UnexpectedStatusCodeError(
`Failed to get pool by ID ${id}`,
response.status,
await response.text()
);
return res.body;
}
async listByAccountId(
accountId: string,
batchAccountId: string,
opts?: OperationOptions
): Promise<PoolOutput[]> {
const response = await getHttpClient().get(
`${getArmUrl()}${accountId}/pools?api-version=${
BatchApiVersion.arm
}`,
{
metadata: buildRequestMetadata(opts),
}
);
const armBatchClient = createARMBatchClient({
baseUrl: getArmUrl(),
});
if (response.status === 200) {
const json = (await response.json()) as ListPoolsResultOutput;
return json.value ?? [];
const { subscriptionId, resourceGroupName, batchAccountName } =
parseBatchAccountIdInfo(batchAccountId);
const res = await armBatchClient
.path(
POOLS_PATH,
subscriptionId,
resourceGroupName,
batchAccountName
)
.get();
if (isUnexpected(res)) {
throw createArmUnexpectedStatusCodeError(res);
}
throw new UnexpectedStatusCodeError(
`Failed to list pools under account ${accountId}`,
response.status,
await response.text()
);
return res.body.value ?? [];
}
async patch(pool: Pool, opts?: OperationOptions): Promise<PoolOutput> {
if (!pool.id) {
throw new Error("Pool ID must be defined");
async patch(
poolArmId: string,
pool: Pool,
opts?: OperationOptions
): Promise<PoolOutput> {
const armBatchClient = createARMBatchClient({
baseUrl: getArmUrl(),
});
const {
subscriptionId,
resourceGroupName,
batchAccountName,
poolName,
} = parsePoolArmIdInfo(poolArmId);
const res = await armBatchClient
.path(
SINGLE_POOL_PATH,
subscriptionId,
resourceGroupName,
batchAccountName,
poolName
)
.patch({
body: pool,
headers: {},
});
if (isUnexpected(res)) {
throw createArmUnexpectedStatusCodeError(res);
}
const response = await getHttpClient().patch(
`${getArmUrl()}${pool.id}?api-version=${BatchApiVersion.arm}`,
{
headers: {
[StandardHttpHeaders.ContentType]: MediaType.Json,
},
body: JSON.stringify(pool),
metadata: buildRequestMetadata(opts),
}
);
if (response.status === 200) {
return (await response.json()) as PoolOutput;
}
throw new UnexpectedStatusCodeError(
`Failed to patch pool ${pool.id}`,
response.status,
await response.text()
);
return res.body;
}
}

Просмотреть файл

@ -9,6 +9,6 @@ export {
PoolDisableAutoScaleParameters,
PoolStopResizeParameters,
PoolOutput,
} from "@batch/arm-batch-rest";
} from "../internal/arm-batch-rest";
export type NodeCommunicationMode = "Default" | "Simplified" | "Classic";

Просмотреть файл

@ -2,8 +2,18 @@ import { OperationOptions } from "@azure/bonito-core";
import { Pool, PoolOutput } from "./pool-models";
export interface PoolService {
createOrUpdate(pool: Pool, opts?: OperationOptions): Promise<PoolOutput>;
get(id: string, opts?: OperationOptions): Promise<PoolOutput | undefined>;
listByAccountId(accountId: string): Promise<PoolOutput[]>;
patch(pool: Pool, opts?: OperationOptions): Promise<PoolOutput>;
createOrUpdate(poolArmId: string, pool: Pool): Promise<PoolOutput>;
get(
poolArmId: string,
opts?: OperationOptions
): Promise<PoolOutput | undefined>;
listByAccountId(
accountId: string,
opts?: OperationOptions
): Promise<PoolOutput[]>;
patch(
poolArmId: string,
pool: Pool,
opts?: OperationOptions
): Promise<PoolOutput>;
}

Просмотреть файл

@ -13,6 +13,10 @@ import {
} from "@azure/bonito-core";
import { AbstractFakeSet, FakeSet } from "@azure/bonito-core/lib/test-util";
import { BatchAccountOutput } from "../account/account-models";
import {
BatchNodeOutput,
BatchNodeVMExtensionOutput,
} from "../node/node-models";
import { Pool, PoolOutput } from "../pool/pool-models";
/**
@ -59,9 +63,16 @@ export interface BatchFakeSet extends FakeSet {
* @param subscriptionId The full ARM resource ID of the account
*/
listPoolsByAccount(accountId: string): PoolOutput[];
listBatchNodes(poolId: string): BatchNodeOutput[];
listBatchNodeExtensions(nodeId: string): BatchNodeVMExtensionOutput[];
}
export abstract class AbstractBatchFakeSet extends AbstractFakeSet {
export abstract class AbstractBatchFakeSet
extends AbstractFakeSet
implements BatchFakeSet
{
abstract defaultTenantArmId: string;
protected abstract batchAccounts: {
@ -69,6 +80,12 @@ export abstract class AbstractBatchFakeSet extends AbstractFakeSet {
};
protected abstract batchPools: { [poolId: string]: PoolOutput };
protected abstract batchNodes: { [poolId: string]: BatchNodeOutput[] };
protected abstract batchNodeExtensions: {
[nodeId: string]: BatchNodeVMExtensionOutput[];
};
getBatchAccount(batchAccountId: string): BatchAccountOutput | undefined {
return this.batchAccounts[batchAccountId.toLowerCase()];
}
@ -126,6 +143,14 @@ export abstract class AbstractBatchFakeSet extends AbstractFakeSet {
return this.patchPool(pool);
}
listBatchNodes(poolId: string): BatchNodeOutput[] {
return this.batchNodes[poolId] ?? [];
}
listBatchNodeExtensions(nodeId: string): BatchNodeVMExtensionOutput[] {
return this.batchNodeExtensions[nodeId] ?? [];
}
}
export class BasicBatchFakeSet extends AbstractBatchFakeSet {
@ -507,6 +532,7 @@ export class BasicBatchFakeSet extends AbstractBatchFakeSet {
userAccounts: [
{
name: "username1",
password: "password1",
elevationLevel: "Admin",
linuxUserConfiguration: {
uid: 1234,
@ -526,6 +552,84 @@ export class BasicBatchFakeSet extends AbstractBatchFakeSet {
},
},
};
batchNodes: { [poolId: string]: BatchNodeOutput[] } = {
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/supercomputing/providers/Microsoft.Batch/batchAccounts/hobo/pools/hobopool1":
[
{
id: "tvmps_id1",
url: "https://account.region.batch.azure.com/pools/hobopool1/nodes/tvmps_id1",
state: "starting",
schedulingState: "enabled",
stateTransitionTime: "2023-11-09T07:20:55.000Z",
allocationTime: "2023-11-09T07:20:45.000Z",
ipAddress: "10.0.0.4",
affinityId:
"TVM:tvmps_7b5797648c5d43f7a15b952e5ada3c082ccac8de5eb95f5518ab1242bc79aa3b_d",
vmSize: "standard_d2_v2",
totalTasksRun: 0,
runningTasksCount: 0,
runningTaskSlotsCount: 0,
totalTasksSucceeded: 0,
isDedicated: true,
endpointConfiguration: {
inboundEndpoints: [
{
name: "SSHRule.0",
protocol: "tcp",
publicIPAddress: "20.24.241.25",
publicFQDN:
"cloudservice.region.cloudapp.azure.com",
frontendPort: 50000,
backendPort: 3389,
},
],
},
virtualMachineInfo: {
imageReference: {
publisher: "microsoftwindowsserver",
offer: "windowsserver",
sku: "2022-datacenter",
version: "latest",
exactVersion: "20348.2031.231006",
},
},
},
],
};
batchNodeExtensions: { [nodeId: string]: BatchNodeVMExtensionOutput[] } = {
tvmps_id1: [
{
provisioningState: "Succeeded",
instanceView: {
name: "CustomExtension100",
statuses: [
{
code: "ProvisioningState/succeeded",
level: "0",
displayStatus: "Provisioning succeeded",
message:
"ExtensionOperation:enable. Status:Success",
time: "11/9/2023 7:44:19 AM",
},
],
},
vmExtension: {
name: "CustomExtension100",
publisher: "Microsoft.Azure.Geneva",
type: "GenevaMonitoring",
typeHandlerVersion: "2.0",
autoUpgradeMinorVersion: true,
enableAutomaticUpgrade: true,
settings: {
applicationId: "settings1",
version: "3.3.3",
},
},
},
],
};
}
/**

Просмотреть файл

@ -0,0 +1,127 @@
import { HttpResponse as AzureCoreHttpResponse } from "@azure-rest/core-client";
import { UnexpectedStatusCodeError } from "@azure/bonito-core";
import { CloudErrorOutput } from "./internal/arm-batch-rest";
import { BatchErrorOutput } from "./internal/batch-rest";
const batchAccountIdRegex =
/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/Microsoft.Batch\/batchAccounts\/(.*)/i;
const poolArmIdRegex =
/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/Microsoft.Batch\/batchAccounts\/(.*)\/pools\/(.*)/i;
interface ErrorResponse extends AzureCoreHttpResponse {
status: string;
body: BatchErrorOutput | CloudErrorOutput;
}
export interface BatchAccountIdInfo {
subscriptionId: string;
resourceGroupName: string;
batchAccountName: string;
}
export function createArmUnexpectedStatusCodeError(
res: ErrorResponse
): UnexpectedStatusCodeError {
return createUnexpectedStatusCodeError(
`The Batch management plane returned an unexpected status code`,
res
);
}
export function createBatchUnexpectedStatusCodeError(
res: ErrorResponse
): UnexpectedStatusCodeError {
return createUnexpectedStatusCodeError(
`The Batch data plane returned an unexpected status code`,
res
);
}
export function createUnexpectedStatusCodeError(
msg: string,
res: ErrorResponse
): UnexpectedStatusCodeError {
return new UnexpectedStatusCodeError(
msg,
+res.status,
JSON.stringify(res.body)
);
}
/**
*
* @param oriBatchAccountId is of the form:
* /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Batch/batchAccounts/{accountName}
* case-insensitive
*/
export function parseBatchAccountIdInfo(
oriBatchAccountId: string
): BatchAccountIdInfo {
// use regex to parse the batch account id
const batchAccountId = ensureRelativeUrl(oriBatchAccountId);
const match = batchAccountId.match(batchAccountIdRegex);
if (!match) {
throw new Error(`Unable to parse batch account id: ${batchAccountId}`);
}
const [, subscriptionId, resourceGroupName, batchAccountName] = match;
return {
subscriptionId,
resourceGroupName,
batchAccountName,
};
}
/**
*
* @param oriPoolArmId is of the form:
* /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Batch/batchAccounts/{accountName}/pools/{poolName}F
* case-insensitive
*/
export function parsePoolArmIdInfo(oriPoolArmId: string): {
subscriptionId: string;
resourceGroupName: string;
batchAccountName: string;
poolName: string;
} {
// use regex to parse the batch account id
const poolArmId = ensureRelativeUrl(oriPoolArmId);
const match = poolArmId.match(poolArmIdRegex);
if (!match) {
throw new Error(`Unable to parse pool ARM id: ${poolArmId}`);
}
const [, subscriptionId, resourceGroupName, batchAccountName, poolName] =
match;
return {
subscriptionId,
resourceGroupName,
batchAccountName,
poolName,
};
}
export function ensureRelativeUrl(untrustedUrlString: string): string {
let relative = null;
try {
// Treat input as absolute, make relative
const absolute = new URL(untrustedUrlString);
relative = absolute.href.slice(absolute.origin.length);
} catch {
// Input was already relative
relative = untrustedUrlString;
}
if (!relative) {
relative = "";
}
if (relative != "" && !relative.startsWith("/")) {
relative = "/" + relative;
}
// Normalize any leading '/' or '\' characters
relative = relative.replace(/^[/\\]+/, "/");
// Return relative url
return relative;
}

Просмотреть файл

@ -12,8 +12,8 @@ generate-metadata: false
generate-test: false
generate-sample: false
license-header: MICROSOFT_MIT_NO_VERSION
output-folder: ../
source-code-folder-path: ./src/generated
output-folder: ../src/internal/arm-batch-rest
source-code-folder-path: ./generated
input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/batch/resource-manager/Microsoft.Batch/stable/2023-05-01/BatchManagement.json
package-version: 1.0.0-beta.1
rest-level-client: true

Просмотреть файл

@ -22,6 +22,7 @@ import {
BatchBrowserDependencyFactories,
BatchFormControlResolver,
} from "@batch/ui-react";
import { FakeNodeService } from "@batch/ui-service";
import { BatchDependencyName } from "@batch/ui-service/lib/environment";
import { FakePoolService } from "@batch/ui-service/lib/pool";
import * as React from "react";
@ -63,6 +64,7 @@ export async function init(rootEl: HTMLElement): Promise<void> {
new FakeLocationService(),
[DependencyName.Notifier]: () => new AlertNotifier(), // TODO: update with real notification implementation
[BatchDependencyName.PoolService]: () => new FakePoolService(),
[BatchDependencyName.NodeService]: () => new FakeNodeService(),
[DependencyName.ResourceGroupService]: () =>
new FakeResourceGroupService(),
[DependencyName.StorageAccountService]: () =>