import type { DockerHost } from './classes.host.js'; import type { IConfigCreationDescriptor, IConfigSpec, } from './interfaces/config.js'; import type { TLabels } from './interfaces/label.js'; import { DockerResource } from './classes.base.js'; import { assertDockerResponseStatus, encodeDockerResourceData, formatDockerResponseBody, } from './helpers.docker.js'; export class DockerConfig extends DockerResource { /** * Internal: Get all configs * Public API: Use dockerHost.listConfigs() instead */ public static async _list( dockerHostArg: DockerHost, ): Promise { const response = await dockerHostArg.request('GET', '/configs'); assertDockerResponseStatus('Docker config list', 200, response); return response.body.map((configArg: Record) => { const config = new DockerConfig(dockerHostArg); Object.assign(config, configArg); return config; }); } /** * Internal: Get config by ID * Public API: Use dockerHost.getConfigById(id) instead */ public static async _fromId( dockerHostArg: DockerHost, idArg: string, ): Promise { const response = await dockerHostArg.request( 'GET', `/configs/${encodeURIComponent(idArg)}`, ); if (response.statusCode === 404) { return undefined; } assertDockerResponseStatus(`Docker config inspect "${idArg}"`, 200, response); const config = new DockerConfig(dockerHostArg); Object.assign(config, response.body); return config; } /** * Internal: Get config by name * Public API: Use dockerHost.getConfigByName(name) instead */ public static async _fromName( dockerHostArg: DockerHost, nameArg: string, ): Promise { const configs = await this._list(dockerHostArg); return configs.find((configArg) => configArg.Spec.Name === nameArg); } /** * Internal: Create a config * Public API: Use dockerHost.createConfig(descriptor) instead */ public static async _create( dockerHostArg: DockerHost, configDescriptorArg: IConfigCreationDescriptor, ): Promise { const response = await dockerHostArg.request('POST', '/configs/create', { Name: configDescriptorArg.name, Labels: { ...configDescriptorArg.labels, version: configDescriptorArg.version, }, Data: encodeDockerResourceData(configDescriptorArg.contentArg), }); assertDockerResponseStatus('Docker config create', 201, response); const createdId = response.body?.ID; if (typeof createdId !== 'string' || createdId.length === 0) { throw new Error( `Docker config create failed: expected response body.ID to be a nonempty string; response body: ${formatDockerResponseBody(response.body)}`, ); } const createdConfig = await DockerConfig._fromId(dockerHostArg, createdId); if (!createdConfig) { throw new Error( `Docker config create failed: direct inspect did not find created ID "${createdId}"`, ); } return createdConfig; } public ID!: string; public Spec!: IConfigSpec; public Version!: { Index: number; }; constructor(dockerHostArg: DockerHost) { super(dockerHostArg); } /** * Refreshes this config through direct ID inspection. * @throws If Docker no longer has the config or inspection fails. */ public async refresh(): Promise { const updatedConfig = await DockerConfig._fromId(this.dockerHost, this.ID); if (!updatedConfig) { throw new Error(`Docker config refresh failed: config "${this.ID}" was not found`); } Object.assign(this, updatedConfig); } /** * Replaces the complete label map, preserves the inspected Spec, and refreshes. * @param replacementLabelsArg The complete replacement label map. */ public async updateLabels( replacementLabelsArg: TLabels, ): Promise { const response = await this.dockerHost.request( 'POST', `/configs/${encodeURIComponent(this.ID)}/update?version=${this.Version.Index}`, { ...this.Spec, Labels: replacementLabelsArg, }, ); assertDockerResponseStatus( `Docker config label update "${this.ID}"`, 200, response, ); await this.refresh(); } /** * Removes this config. Docker must respond with status 204. */ public async remove(): Promise { const response = await this.dockerHost.request( 'DELETE', `/configs/${encodeURIComponent(this.ID)}`, ); assertDockerResponseStatus( `Docker config remove "${this.ID}"`, 204, response, ); } /** * Returns the version label stored in the config Spec. */ public async getVersion(): Promise { return this.Spec.Labels.version; } }