BREAKING CHANGE(DockerHost): Refactor public API to DockerHost facade; introduce DockerResource base; make resource static methods internal; support flexible descriptors and stream compatibility
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import { DockerHost } from './classes.host.js';
|
||||
import { DockerResource } from './classes.base.js';
|
||||
import { logger } from './logger.js';
|
||||
|
||||
/**
|
||||
* represents a docker image on the remote docker host
|
||||
*/
|
||||
export class DockerImage {
|
||||
// STATIC
|
||||
public static async getImages(dockerHost: DockerHost) {
|
||||
export class DockerImage extends DockerResource {
|
||||
// STATIC (Internal - prefixed with _ to indicate internal use)
|
||||
|
||||
/**
|
||||
* Internal: Get all images
|
||||
* Public API: Use dockerHost.getImages() instead
|
||||
*/
|
||||
public static async _list(dockerHost: DockerHost) {
|
||||
const images: DockerImage[] = [];
|
||||
const response = await dockerHost.request('GET', '/images/json');
|
||||
for (const imageObject of response.body) {
|
||||
@@ -17,11 +23,15 @@ export class DockerImage {
|
||||
return images;
|
||||
}
|
||||
|
||||
public static async getImageByName(
|
||||
/**
|
||||
* Internal: Get image by name
|
||||
* Public API: Use dockerHost.getImageByName(name) instead
|
||||
*/
|
||||
public static async _fromName(
|
||||
dockerHost: DockerHost,
|
||||
imageNameArg: string,
|
||||
) {
|
||||
const images = await this.getImages(dockerHost);
|
||||
const images = await this._list(dockerHost);
|
||||
const result = images.find((image) => {
|
||||
if (image.RepoTags) {
|
||||
return image.RepoTags.includes(imageNameArg);
|
||||
@@ -32,7 +42,11 @@ export class DockerImage {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async createFromRegistry(
|
||||
/**
|
||||
* Internal: Create image from registry
|
||||
* Public API: Use dockerHost.createImageFromRegistry(descriptor) instead
|
||||
*/
|
||||
public static async _createFromRegistry(
|
||||
dockerHostArg: DockerHost,
|
||||
optionsArg: {
|
||||
creationObject: interfaces.IImageCreationDescriptor;
|
||||
@@ -76,7 +90,7 @@ export class DockerImage {
|
||||
'info',
|
||||
`Successfully pulled image ${imageUrlObject.imageUrl} from the registry`,
|
||||
);
|
||||
const image = await DockerImage.getImageByName(
|
||||
const image = await DockerImage._fromName(
|
||||
dockerHostArg,
|
||||
imageUrlObject.imageOriginTag,
|
||||
);
|
||||
@@ -87,11 +101,10 @@ export class DockerImage {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dockerHostArg
|
||||
* @param tarStreamArg
|
||||
* Internal: Create image from tar stream
|
||||
* Public API: Use dockerHost.createImageFromTarStream(stream, descriptor) instead
|
||||
*/
|
||||
public static async createFromTarStream(
|
||||
public static async _createFromTarStream(
|
||||
dockerHostArg: DockerHost,
|
||||
optionsArg: {
|
||||
creationObject: interfaces.IImageCreationDescriptor;
|
||||
@@ -161,11 +174,11 @@ export class DockerImage {
|
||||
}
|
||||
|
||||
// Now try to look up that image by the "loadedImageTag".
|
||||
// Depending on Docker’s response, it might be something like:
|
||||
// Depending on Docker's response, it might be something like:
|
||||
// "myrepo/myimage:latest" OR "sha256:someHash..."
|
||||
// If Docker gave you an ID (e.g. "sha256:..."), you may need a separate
|
||||
// DockerImage.getImageById method; or if you prefer, you can treat it as a name.
|
||||
const newlyImportedImage = await DockerImage.getImageByName(
|
||||
const newlyImportedImage = await DockerImage._fromName(
|
||||
dockerHostArg,
|
||||
loadedImageTag,
|
||||
);
|
||||
@@ -192,15 +205,15 @@ export class DockerImage {
|
||||
);
|
||||
}
|
||||
|
||||
public static async buildImage(dockerHostArg: DockerHost, dockerImageTag) {
|
||||
/**
|
||||
* Internal: Build image from Dockerfile
|
||||
* Public API: Use dockerHost.buildImage(tag) instead
|
||||
*/
|
||||
public static async _build(dockerHostArg: DockerHost, dockerImageTag) {
|
||||
// TODO: implement building an image
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
// references
|
||||
public dockerHost: DockerHost;
|
||||
|
||||
// properties
|
||||
// INSTANCE PROPERTIES
|
||||
/**
|
||||
* the tags for an image
|
||||
*/
|
||||
@@ -215,13 +228,28 @@ export class DockerImage {
|
||||
public Size: number;
|
||||
public VirtualSize: number;
|
||||
|
||||
constructor(dockerHostArg, dockerImageObjectArg: any) {
|
||||
this.dockerHost = dockerHostArg;
|
||||
constructor(dockerHostArg: DockerHost, dockerImageObjectArg: any) {
|
||||
super(dockerHostArg);
|
||||
Object.keys(dockerImageObjectArg).forEach((keyArg) => {
|
||||
this[keyArg] = dockerImageObjectArg[keyArg];
|
||||
});
|
||||
}
|
||||
|
||||
// INSTANCE METHODS
|
||||
|
||||
/**
|
||||
* Refreshes this image's state from the Docker daemon
|
||||
*/
|
||||
public async refresh(): Promise<void> {
|
||||
if (!this.RepoTags || this.RepoTags.length === 0) {
|
||||
throw new Error('Cannot refresh image without RepoTags');
|
||||
}
|
||||
const updated = await DockerImage._fromName(this.dockerHost, this.RepoTags[0]);
|
||||
if (updated) {
|
||||
Object.assign(this, updated);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tag an image
|
||||
* @param newTag
|
||||
@@ -234,7 +262,7 @@ export class DockerImage {
|
||||
* pulls the latest version from the registry
|
||||
*/
|
||||
public async pullLatestImageFromRegistry(): Promise<boolean> {
|
||||
const updatedImage = await DockerImage.createFromRegistry(this.dockerHost, {
|
||||
const updatedImage = await DockerImage._createFromRegistry(this.dockerHost, {
|
||||
creationObject: {
|
||||
imageUrl: this.RepoTags[0],
|
||||
},
|
||||
@@ -244,6 +272,25 @@ export class DockerImage {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this image from the Docker daemon
|
||||
*/
|
||||
public async remove(options?: { force?: boolean; noprune?: boolean }): Promise<void> {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (options?.force) queryParams.append('force', '1');
|
||||
if (options?.noprune) queryParams.append('noprune', '1');
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const response = await this.dockerHost.request(
|
||||
'DELETE',
|
||||
`/images/${encodeURIComponent(this.Id)}${queryString ? '?' + queryString : ''}`,
|
||||
);
|
||||
|
||||
if (response.statusCode >= 300) {
|
||||
throw new Error(`Failed to remove image: ${response.statusCode}`);
|
||||
}
|
||||
}
|
||||
|
||||
// get stuff
|
||||
public async getVersion() {
|
||||
if (this.Labels && this.Labels.version) {
|
||||
|
||||
Reference in New Issue
Block a user