docker/ts/classes.image.ts

194 lines
5.6 KiB
TypeScript
Raw Normal View History

import * as plugins from './plugins.js';
2022-10-17 07:36:35 +00:00
import * as interfaces from './interfaces/index.js';
import { DockerHost } from './classes.host.js';
import { logger } from './logger.js';
2018-07-16 21:52:50 +00:00
/**
* represents a docker image on the remote docker host
*/
2018-07-16 21:52:50 +00:00
export class DockerImage {
2019-08-14 12:19:45 +00:00
// STATIC
2019-08-15 16:50:13 +00:00
public static async getImages(dockerHost: DockerHost) {
const images: DockerImage[] = [];
const response = await dockerHost.request('GET', '/images/json');
for (const imageObject of response.body) {
images.push(new DockerImage(dockerHost, imageObject));
}
return images;
}
public static async getImageByName(dockerHost: DockerHost, imageNameArg: string) {
2019-08-15 17:00:17 +00:00
const images = await this.getImages(dockerHost);
2020-09-30 16:35:24 +00:00
const result = images.find((image) => {
2019-09-13 12:40:38 +00:00
if (image.RepoTags) {
return image.RepoTags.includes(imageNameArg);
} else {
return false;
}
2019-08-15 17:00:17 +00:00
});
2019-09-13 12:40:38 +00:00
return result;
2019-08-15 17:00:17 +00:00
}
2019-08-14 18:56:57 +00:00
public static async createFromRegistry(
dockerHostArg: DockerHost,
optionsArg: {
creationObject: interfaces.IImageCreationDescriptor
}
2019-08-14 18:56:57 +00:00
): Promise<DockerImage> {
2019-08-16 12:46:48 +00:00
// lets create a sanatized imageUrlObject
const imageUrlObject: {
imageUrl: string;
imageTag: string;
imageOriginTag: string;
} = {
imageUrl: optionsArg.creationObject.imageUrl,
imageTag: optionsArg.creationObject.imageTag,
2020-09-30 16:35:24 +00:00
imageOriginTag: null,
2019-08-16 12:46:48 +00:00
};
if (imageUrlObject.imageUrl.includes(':')) {
const imageUrl = imageUrlObject.imageUrl.split(':')[0];
const imageTag = imageUrlObject.imageUrl.split(':')[1];
if (imageUrlObject.imageTag) {
throw new Error(
2019-09-13 16:20:12 +00:00
`imageUrl ${imageUrlObject.imageUrl} can't be tagged with ${imageUrlObject.imageTag} because it is already tagged with ${imageTag}`
2019-08-16 12:46:48 +00:00
);
} else {
2019-09-12 12:45:36 +00:00
imageUrlObject.imageUrl = imageUrl;
2019-08-16 12:46:48 +00:00
imageUrlObject.imageTag = imageTag;
}
2019-08-16 16:21:55 +00:00
} else if (!imageUrlObject.imageTag) {
imageUrlObject.imageTag = 'latest';
2019-08-16 12:46:48 +00:00
}
imageUrlObject.imageOriginTag = `${imageUrlObject.imageUrl}:${imageUrlObject.imageTag}`;
// lets actually create the image
2019-08-15 16:50:13 +00:00
const response = await dockerHostArg.request(
'POST',
`/images/create?fromImage=${encodeURIComponent(
2019-08-16 12:46:48 +00:00
imageUrlObject.imageUrl
)}&tag=${encodeURIComponent(imageUrlObject.imageTag)}`
2019-08-15 16:50:13 +00:00
);
if (response.statusCode < 300) {
2020-09-30 16:35:24 +00:00
logger.log('info', `Successfully pulled image ${imageUrlObject.imageUrl} from the registry`);
const image = await DockerImage.getImageByName(dockerHostArg, imageUrlObject.imageOriginTag);
2019-08-15 16:50:13 +00:00
return image;
} else {
2020-09-30 16:27:43 +00:00
logger.log('error', `Failed at the attempt of creating a new image`);
2019-08-15 16:50:13 +00:00
}
}
2019-08-14 12:19:45 +00:00
/**
*
* @param dockerHostArg
* @param tarStreamArg
*/
public static async createFromTarStream(dockerHostArg: DockerHost, optionsArg: {
creationObject: interfaces.IImageCreationDescriptor,
tarStream: plugins.smartstream.stream.Readable,
}) {
const response = await dockerHostArg.requestStreaming('POST', '/images/load', optionsArg.tarStream);
return response;
}
2019-08-15 16:50:13 +00:00
public static async tagImageByIdOrName(
dockerHost: DockerHost,
idOrNameArg: string,
newTagArg: string
) {
const response = await dockerHost.request(
'POST',
`/images/${encodeURIComponent(idOrNameArg)}/${encodeURIComponent(newTagArg)}`
);
2019-08-14 12:19:45 +00:00
}
2019-08-15 16:50:13 +00:00
public static async buildImage(dockerHostArg: DockerHost, dockerImageTag) {
// TODO: implement building an image
}
2019-08-14 12:19:45 +00:00
// INSTANCE
2019-08-15 16:50:13 +00:00
// references
public dockerHost: DockerHost;
// properties
2018-07-16 21:52:50 +00:00
/**
* the tags for an image
*/
2019-08-15 16:50:13 +00:00
public Containers: number;
public Created: number;
public Id: string;
public Labels: interfaces.TLabels;
public ParentId: string;
public RepoDigests: string[];
public RepoTags: string[];
public SharedSize: number;
public Size: number;
public VirtualSize: number;
constructor(dockerHostArg, dockerImageObjectArg: any) {
this.dockerHost = dockerHostArg;
2020-09-30 16:35:24 +00:00
Object.keys(dockerImageObjectArg).forEach((keyArg) => {
2019-08-15 16:50:13 +00:00
this[keyArg] = dockerImageObjectArg[keyArg];
});
}
2018-07-16 21:52:50 +00:00
2019-09-13 14:57:21 +00:00
/**
* tag an image
* @param newTag
*/
public async tagImage(newTag) {
throw new Error('.tagImage is not yet implemented');
}
2019-08-15 17:00:17 +00:00
2019-08-14 12:19:45 +00:00
/**
2019-08-15 16:50:13 +00:00
* pulls the latest version from the registry
2019-08-14 12:19:45 +00:00
*/
2019-08-14 18:56:57 +00:00
public async pullLatestImageFromRegistry(): Promise<boolean> {
2019-08-15 16:50:13 +00:00
const updatedImage = await DockerImage.createFromRegistry(this.dockerHost, {
creationObject: {
imageUrl: this.RepoTags[0],
},
2019-08-15 16:50:13 +00:00
});
Object.assign(this, updatedImage);
// TODO: Compare image digists before and after
2019-08-14 12:19:45 +00:00
return true;
2018-07-16 21:52:50 +00:00
}
2019-09-13 12:45:35 +00:00
// get stuff
public async getVersion() {
2019-09-20 14:29:43 +00:00
if (this.Labels && this.Labels.version) {
return this.Labels.version;
} else {
return '0.0.0';
2019-09-20 14:29:43 +00:00
}
2019-09-13 12:45:35 +00:00
}
/**
* exports an image to a tar ball
*/
public async exportToTarStream(): Promise<plugins.smartstream.stream.Readable> {
2024-06-09 22:15:01 +00:00
logger.log('info', `Exporting image ${this.RepoTags[0]} to tar stream.`);
const response = await this.dockerHost.requestStreaming('GET', `/images/${encodeURIComponent(this.RepoTags[0])}/get`);
let counter = 0;
const webduplexStream = new plugins.smartstream.SmartDuplex({
writeFunction: async (chunk, tools) => {
if (counter % 1000 === 0)
console.log(`Got chunk: ${counter}`);
counter++;
return chunk;
}
});
response.on('data', (chunk) => {
if (!webduplexStream.write(chunk)) {
response.pause();
webduplexStream.once('drain', () => {
response.resume();
})
};
});
response.on('end', () => {
webduplexStream.end();
})
return webduplexStream;
}
2018-07-17 06:39:37 +00:00
}