mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-05-24 02:08:24 +00:00
feat(extension-api): adding stats container api (#6212)
* feat: adding stats container api Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> * test(extension-loader): ensuring containerEngine statsContainer is working as expected Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> * refactor(extension-api): resolving comments Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> * Revert "refactor(extension-api): resolving comments" This reverts commit b8b8b63098686bd4871eb1befa09dbee6e225c2d. Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> * Apply suggestions from code review Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> --------- Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com>
This commit is contained in:
parent
9aa4169b50
commit
fefd722f7e
3 changed files with 187 additions and 0 deletions
150
packages/extension-api/src/extension-api.d.ts
vendored
150
packages/extension-api/src/extension-api.d.ts
vendored
|
|
@ -2655,6 +2655,130 @@ declare module '@podman-desktop/api' {
|
|||
title: string;
|
||||
}
|
||||
|
||||
export interface PidsStats {
|
||||
current?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface BlkioStatEntry {
|
||||
major: number;
|
||||
minor: number;
|
||||
op: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface BlkioStats {
|
||||
io_service_bytes_recursive: BlkioStatEntry[];
|
||||
io_serviced_recursive: BlkioStatEntry[];
|
||||
io_queue_recursive: BlkioStatEntry[];
|
||||
io_service_time_recursive: BlkioStatEntry[];
|
||||
io_wait_time_recursive: BlkioStatEntry[];
|
||||
io_merged_recursive: BlkioStatEntry[];
|
||||
io_time_recursive: BlkioStatEntry[];
|
||||
sectors_recursive: BlkioStatEntry[];
|
||||
}
|
||||
|
||||
export interface StorageStats {
|
||||
read_count_normalized?: number;
|
||||
read_size_bytes?: number;
|
||||
write_count_normalized?: number;
|
||||
write_size_bytes?: number;
|
||||
}
|
||||
|
||||
export interface NetworkStats {
|
||||
[name: string]: {
|
||||
rx_bytes: number;
|
||||
rx_dropped: number;
|
||||
rx_errors: number;
|
||||
rx_packets: number;
|
||||
tx_bytes: number;
|
||||
tx_dropped: number;
|
||||
tx_errors: number;
|
||||
tx_packets: number;
|
||||
endpoint_id?: string; // not used on linux
|
||||
instance_id?: string; // not used on linux
|
||||
};
|
||||
}
|
||||
|
||||
export interface MemoryStats {
|
||||
// Linux Memory Stats
|
||||
stats: {
|
||||
total_pgmajfault: number;
|
||||
cache: number;
|
||||
mapped_file: number;
|
||||
total_inactive_file: number;
|
||||
pgpgout: number;
|
||||
rss: number;
|
||||
total_mapped_file: number;
|
||||
writeback: number;
|
||||
unevictable: number;
|
||||
pgpgin: number;
|
||||
total_unevictable: number;
|
||||
pgmajfault: number;
|
||||
total_rss: number;
|
||||
total_rss_huge: number;
|
||||
total_writeback: number;
|
||||
total_inactive_anon: number;
|
||||
rss_huge: number;
|
||||
hierarchical_memory_limit: number;
|
||||
total_pgfault: number;
|
||||
total_active_file: number;
|
||||
active_anon: number;
|
||||
total_active_anon: number;
|
||||
total_pgpgout: number;
|
||||
total_cache: number;
|
||||
inactive_anon: number;
|
||||
active_file: number;
|
||||
pgfault: number;
|
||||
inactive_file: number;
|
||||
total_pgpgin: number;
|
||||
};
|
||||
max_usage: number;
|
||||
usage: number;
|
||||
failcnt: number;
|
||||
limit: number;
|
||||
|
||||
// Windows Memory Stats
|
||||
commitbytes?: number;
|
||||
commitpeakbytes?: number;
|
||||
privateworkingset?: number;
|
||||
}
|
||||
|
||||
export interface CPUUsage {
|
||||
percpu_usage: number[];
|
||||
usage_in_usermode: number;
|
||||
total_usage: number;
|
||||
usage_in_kernelmode: number;
|
||||
}
|
||||
|
||||
export interface ThrottlingData {
|
||||
periods: number;
|
||||
throttled_periods: number;
|
||||
throttled_time: number;
|
||||
}
|
||||
|
||||
export interface CPUStats {
|
||||
cpu_usage: CPUUsage;
|
||||
system_cpu_usage: number;
|
||||
online_cpus: number;
|
||||
throttling_data: ThrottlingData;
|
||||
}
|
||||
|
||||
export interface ContainerStatsInfo {
|
||||
engineId: string;
|
||||
engineName: string;
|
||||
read: string;
|
||||
preread: string;
|
||||
pids_stats?: PidsStats;
|
||||
blkio_stats?: BlkioStats;
|
||||
num_procs: number;
|
||||
storage_stats?: StorageStats;
|
||||
networks: NetworkStats;
|
||||
memory_stats: MemoryStats;
|
||||
cpu_stats: CPUStats;
|
||||
precpu_stats: CPUStats;
|
||||
}
|
||||
|
||||
export interface BuildImageOptions {
|
||||
/**
|
||||
* Specifies a Containerfile which contains instructions for building the image
|
||||
|
|
@ -2975,6 +3099,32 @@ declare module '@podman-desktop/api' {
|
|||
callback: (name: string, data: string) => void,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the streamed stats of a running container.
|
||||
*
|
||||
* @param engineId the id of the engine managing the container, obtained from the result of {@link containerEngine.listContainers}
|
||||
* @param id the id or name of the container on this engine, obtained from the result of {@link containerEngine.listContainers} or as the result of {@link containerEngine.createContainer}
|
||||
* @param callback the function called when container stats info are emitted.
|
||||
*
|
||||
* @return A Promise resolving a {@link Disposable} that unregister the callback when called.
|
||||
*
|
||||
* @example
|
||||
* Here is a usage example
|
||||
* ```ts
|
||||
* const disposable = await statsContainer('engineId', 'containerId', (stats: ContainerStatsInfo): void => {
|
||||
* console.log('CPU Usage', stats.cpu_stats.cpu_usage.total_usage);
|
||||
* });
|
||||
*
|
||||
* // When no longer needed
|
||||
* disposable.dispose();
|
||||
* ```
|
||||
*/
|
||||
export function statsContainer(
|
||||
engineId: string,
|
||||
id: string,
|
||||
callback: (stats: ContainerStatsInfo) => void,
|
||||
): Promise<Disposable>;
|
||||
|
||||
/**
|
||||
* Stop an existing container
|
||||
*
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ const containerProviderRegistry: ContainerProviderRegistry = {
|
|||
listPods: vi.fn(),
|
||||
stopPod: vi.fn(),
|
||||
removePod: vi.fn(),
|
||||
getContainerStats: vi.fn(),
|
||||
stopContainerStats: vi.fn(),
|
||||
listImages: vi.fn(),
|
||||
listInfos: vi.fn(),
|
||||
} as unknown as ContainerProviderRegistry;
|
||||
|
|
@ -1654,6 +1656,29 @@ describe('window', async () => {
|
|||
});
|
||||
|
||||
describe('containerEngine', async () => {
|
||||
test('statsContainer ', async () => {
|
||||
vi.mocked(containerProviderRegistry.getContainerStats).mockResolvedValue(99);
|
||||
vi.mocked(containerProviderRegistry.stopContainerStats).mockResolvedValue(undefined);
|
||||
|
||||
const api = extensionLoader.createApi('/path', {});
|
||||
expect(api).toBeDefined();
|
||||
|
||||
const disposable = await api.containerEngine.statsContainer('dummyEngineId', 'dummyContainerId', () => {});
|
||||
expect(disposable).toBeDefined();
|
||||
expect(disposable instanceof Disposable).toBeTruthy();
|
||||
expect(containerProviderRegistry.getContainerStats).toHaveBeenCalledWith(
|
||||
'dummyEngineId',
|
||||
'dummyContainerId',
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
disposable.dispose();
|
||||
await vi.waitUntil(() => {
|
||||
expect(containerProviderRegistry.stopContainerStats).toHaveBeenCalledWith(99);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
test('listImages without option ', async () => {
|
||||
vi.mocked(containerProviderRegistry.listImages).mockResolvedValue([]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1043,6 +1043,18 @@ export class ExtensionLoader {
|
|||
startPod(engineId: string, podId: string): Promise<void> {
|
||||
return containerProviderRegistry.startPod(engineId, podId);
|
||||
},
|
||||
async statsContainer(
|
||||
engineId: string,
|
||||
containerId: string,
|
||||
callback: (stats: containerDesktopAPI.ContainerStatsInfo) => void,
|
||||
): Promise<Disposable> {
|
||||
const identifier = await containerProviderRegistry.getContainerStats(engineId, containerId, callback);
|
||||
return Disposable.create(() => {
|
||||
containerProviderRegistry.stopContainerStats(identifier).catch((err: unknown): void => {
|
||||
console.error('Something went wrong while trying to stop container stats', err);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const authenticationProviderRegistry = this.authenticationProviderRegistry;
|
||||
|
|
|
|||
Loading…
Reference in a new issue