Skip to content

Commit b14fd22

Browse files
committed
Improve container command error handling.
Signed-off-by: Phillip Hoff <phillip@orst.edu>
1 parent 8446d46 commit b14fd22

File tree

3 files changed

+91
-37
lines changed

3 files changed

+91
-37
lines changed

src/tree/durableTaskScheduler/ContainerClient.ts

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,42 +28,51 @@ export class ShellContainerClient implements ContainerClient {
2828
private readonly factory = new CodeContainerClient.ShellStreamCommandRunnerFactory({});
2929

3030
async getContainers(): Promise<DockerContainer[]> {
31-
const commandRunner = this.factory.getCommandRunner();
32-
33-
const containers = await commandRunner(this.dockerClient.listContainers({ running: true }));
34-
35-
return containers.map(
36-
container =>
37-
({
38-
id: container.id,
39-
image: container.image.image as string,
40-
name: container.name,
41-
ports: container.ports.reduce(
42-
(previous, port) => {
43-
previous[port.containerPort] = port.hostPort;
44-
45-
return previous;
46-
},
47-
{})
48-
}));
31+
return await this.withErrorHandling(
32+
async () => {
33+
const commandRunner = this.factory.getCommandRunner();
34+
35+
const containers = await commandRunner(this.dockerClient.listContainers({ running: true }));
36+
37+
return containers.map(
38+
container =>
39+
({
40+
id: container.id,
41+
image: container.image.image as string,
42+
name: container.name,
43+
ports: container.ports.reduce(
44+
(previous, port) => {
45+
previous[port.containerPort] = port.hostPort;
46+
47+
return previous;
48+
},
49+
{})
50+
}));
51+
});
4952
}
5053

5154
async removeContainer(id: string): Promise<void> {
52-
const commandRunner = this.factory.getCommandRunner();
53-
54-
await commandRunner(this.dockerClient.removeContainers({
55-
containers: [id]
56-
}));
55+
await this.withErrorHandling(
56+
async () => {
57+
const commandRunner = this.factory.getCommandRunner();
58+
59+
return await commandRunner(this.dockerClient.removeContainers({
60+
containers: [id]
61+
}));
62+
});
5763
}
5864

5965
async runContainer(image: string): Promise<string> {
60-
const commandRunner = this.factory.getCommandRunner();
66+
const id = await this.withErrorHandling(
67+
async () => {
68+
const commandRunner = this.factory.getCommandRunner();
6169

62-
const id = await commandRunner(this.dockerClient.runContainer({
63-
detached: true,
64-
imageRef: image,
65-
publishAllPorts: true
66-
}));
70+
return await commandRunner(this.dockerClient.runContainer({
71+
detached: true,
72+
imageRef: image,
73+
publishAllPorts: true
74+
}));
75+
});
6776

6877
if (!id) {
6978
throw new Error(localize('startContainerFailed', 'Unable to start the container.'));
@@ -73,10 +82,22 @@ export class ShellContainerClient implements ContainerClient {
7382
}
7483

7584
async stopContainer(id: string): Promise<void> {
76-
const commandRunner = this.factory.getCommandRunner();
85+
await this.withErrorHandling(
86+
async () => {
87+
const commandRunner = this.factory.getCommandRunner();
88+
89+
await commandRunner(this.dockerClient.stopContainers({
90+
container: [id]
91+
}));
92+
});
93+
}
7794

78-
await commandRunner(this.dockerClient.stopContainers({
79-
container: [id]
80-
}));
95+
private async withErrorHandling<T = void>(command: () => Promise<T>): Promise<T> {
96+
try {
97+
return await command();
98+
}
99+
catch (error) {
100+
throw new Error(localize('containerRuntimeError', 'Unable to perform container command. Is a container runtime installed and running?'));
101+
}
81102
}
82103
}

src/tree/durableTaskScheduler/DurableTaskSchedulerEmulatorsWorkspaceResourceModel.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,26 @@ import { localize } from "../../localize";
99
import { treeUtils } from "../../utils/treeUtils";
1010
import {type DurableTaskSchedulerEmulatorClient } from "./DurableTaskSchedulerEmulatorClient";
1111
import { DurableTaskSchedulerEmulatorWorkspaceResourceModel } from "./DurableTaskSchedulerEmulatorWorkspaceResourceModel";
12+
import { DurableTaskSchedulerErrorWorkspaceResourceModel } from "./DurableTaskSchedulerErrorWorkspaceResourceModel";
13+
import { parseError } from "@microsoft/vscode-azext-utils";
1214

1315
export class DurableTaskSchedulerEmulatorsWorkspaceResourceModel implements DurableTaskSchedulerWorkspaceResourceModel {
1416
constructor(private readonly emulatorClient: DurableTaskSchedulerEmulatorClient) {
1517
}
1618

1719
async getChildren(): Promise<DurableTaskSchedulerWorkspaceResourceModel[]> {
18-
const emulators = await this.emulatorClient.getEmulators();
19-
20-
return emulators.map(emulator => new DurableTaskSchedulerEmulatorWorkspaceResourceModel(emulator));
20+
try {
21+
const emulators = await this.emulatorClient.getEmulators();
22+
23+
return emulators.map(emulator => new DurableTaskSchedulerEmulatorWorkspaceResourceModel(emulator));
24+
}
25+
catch (error) {
26+
return [new DurableTaskSchedulerErrorWorkspaceResourceModel(parseError(error).message)];
27+
}
2128
}
2229

2330
getTreeItem(): TreeItem | Thenable<TreeItem> {
24-
const treeItem = new TreeItem(localize('dtsEmulatorsLabel', 'Durable Task Scheduler Emulators'), TreeItemCollapsibleState.Expanded);
31+
const treeItem = new TreeItem(localize('dtsEmulatorsLabel', 'Durable Task Scheduler Emulators'), TreeItemCollapsibleState.Collapsed);
2532

2633
treeItem.contextValue = 'azFunc.dts.emulators';
2734
treeItem.iconPath = treeUtils.getIconPath('durableTaskScheduler/DurableTaskScheduler');
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type ProviderResult, ThemeIcon, TreeItem } from "vscode";
7+
import { type DurableTaskSchedulerWorkspaceResourceModel } from "./DurableTaskSchedulerWorkspaceResourceModel";
8+
9+
export class DurableTaskSchedulerErrorWorkspaceResourceModel implements DurableTaskSchedulerWorkspaceResourceModel {
10+
constructor(
11+
private readonly error: string) {
12+
}
13+
14+
getChildren(): ProviderResult<DurableTaskSchedulerWorkspaceResourceModel[]> {
15+
return [];
16+
}
17+
18+
getTreeItem(): TreeItem | Thenable<TreeItem> {
19+
const treeItem = new TreeItem(this.error);
20+
21+
treeItem.contextValue = 'azFunc.dts.emulatorError';
22+
treeItem.iconPath = new ThemeIcon('warning')
23+
24+
return treeItem;
25+
}
26+
}

0 commit comments

Comments
 (0)