fix(docker): stop containers started with npx playwright docker start (#17316)

This patch makes `npx playwright docker stop` command to stop
containers that were launched with previous playwright version.
This commit is contained in:
Andrey Lushnikov 2022-09-13 17:08:01 -07:00 committed by GitHub
parent dfcd2a273d
commit 210f7b2203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 16 deletions

View File

@ -55,7 +55,7 @@ function addDockerCommand(program: Command) {
dockerCommand.command('stop') dockerCommand.command('stop')
.description('stop docker container') .description('stop docker container')
.action(async function(options) { .action(async function(options) {
await docker.stopPlaywrightContainer(); await docker.stopAllPlaywrightContainers();
}); });
dockerCommand.command('delete-image', { hidden: true }) dockerCommand.command('delete-image', { hidden: true })

View File

@ -28,6 +28,8 @@ import type { FullConfig, Reporter, Suite } from '../../types/testReporter';
const VRT_IMAGE_DISTRO = 'focal'; const VRT_IMAGE_DISTRO = 'focal';
const VRT_IMAGE_NAME = `playwright:local-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`; const VRT_IMAGE_NAME = `playwright:local-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`;
const VRT_CONTAINER_NAME = `playwright-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`; const VRT_CONTAINER_NAME = `playwright-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`;
const VRT_CONTAINER_LABEL_NAME = 'dev.playwright.vrt-service.version';
const VRT_CONTAINER_LABEL_VALUE = '1';
export async function startPlaywrightContainer() { export async function startPlaywrightContainer() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
@ -50,16 +52,15 @@ export async function startPlaywrightContainer() {
].join('\n')); ].join('\n'));
} }
export async function stopPlaywrightContainer() { export async function stopAllPlaywrightContainers() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
const container = await findRunningDockerContainer(); const allContainers = await dockerApi.listContainers();
if (!container) const vrtContainers = allContainers.filter(container => container.labels[VRT_CONTAINER_LABEL_NAME] === VRT_CONTAINER_LABEL_VALUE);
return; await Promise.all(vrtContainers.map(container => dockerApi.stopContainer({
await dockerApi.stopContainer({
containerId: container.containerId, containerId: container.containerId,
waitUntil: 'removed', waitUntil: 'removed',
}); })));
} }
export async function deletePlaywrightImage() { export async function deletePlaywrightImage() {
@ -70,7 +71,7 @@ export async function deletePlaywrightImage() {
return; return;
if (await containerInfo()) if (await containerInfo())
await stopPlaywrightContainer(); await stopAllPlaywrightContainers();
await dockerApi.removeImage(dockerImage.imageId); await dockerApi.removeImage(dockerImage.imageId);
} }
@ -168,7 +169,9 @@ interface ContainerInfo {
} }
async function containerInfo(): Promise<ContainerInfo|undefined> { async function containerInfo(): Promise<ContainerInfo|undefined> {
const container = await findRunningDockerContainer(); const allContainers = await dockerApi.listContainers();
const pwDockerImage = await findDockerImage(VRT_IMAGE_NAME);
const container = allContainers.find(container => container.imageId === pwDockerImage?.imageId && container.state === 'running');
if (!container) if (!container)
return undefined; return undefined;
const logLines = await dockerApi.getContainerLogs(container.containerId); const logLines = await dockerApi.getContainerLogs(container.containerId);
@ -218,6 +221,9 @@ async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
name: VRT_CONTAINER_NAME, name: VRT_CONTAINER_NAME,
autoRemove: true, autoRemove: true,
ports: [5400, 7900], ports: [5400, 7900],
labels: {
[VRT_CONTAINER_LABEL_NAME]: VRT_CONTAINER_LABEL_VALUE,
},
}); });
// Wait for the service to become available. // Wait for the service to become available.
@ -251,10 +257,3 @@ async function findDockerImage(imageName: string): Promise<dockerApi.DockerImage
return images.find(image => image.names.includes(imageName)); return images.find(image => image.names.includes(imageName));
} }
async function findRunningDockerContainer(): Promise<dockerApi.DockerContainer|undefined> {
const containers = await dockerApi.listContainers();
const dockerImage = await findDockerImage(VRT_IMAGE_NAME);
const container = dockerImage ? containers.find(container => container.imageId === dockerImage.imageId) : undefined;
return container?.state === 'running' ? container : undefined;
}

View File

@ -33,6 +33,7 @@ export interface PortBinding {
export interface DockerContainer { export interface DockerContainer {
containerId: string; containerId: string;
labels: Record<string, string>;
imageId: string; imageId: string;
state: 'created'|'restarting'|'running'|'removing'|'paused'|'exited'|'dead'; state: 'created'|'restarting'|'running'|'removing'|'paused'|'exited'|'dead';
names: string[]; names: string[];
@ -51,6 +52,7 @@ export async function listContainers(): Promise<DockerContainer[]> {
hostPort: portInfo.PublicPort, hostPort: portInfo.PublicPort,
containerPort: portInfo.PrivatePort, containerPort: portInfo.PrivatePort,
})) ?? [], })) ?? [],
labels: container.Labels ?? {},
})); }));
} }
@ -58,6 +60,7 @@ interface LaunchContainerOptions {
imageId: string; imageId: string;
autoRemove: boolean; autoRemove: boolean;
command?: string[]; command?: string[];
labels?: Record<string, string>;
ports?: Number[]; ports?: Number[];
name?: string; name?: string;
waitUntil?: 'not-running' | 'next-exit' | 'removed'; waitUntil?: 'not-running' | 'next-exit' | 'removed';
@ -72,6 +75,7 @@ export async function launchContainer(options: LaunchContainerOptions): Promise<
} }
const container = await postJSON(`/containers/create` + (options.name ? '?name=' + options.name : ''), { const container = await postJSON(`/containers/create` + (options.name ? '?name=' + options.name : ''), {
Cmd: options.command, Cmd: options.command,
Labels: options.labels ?? {},
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,
Image: options.imageId, Image: options.imageId,