fix(deps): upgrade core tooling dependencies and adapt Docker client internals for compatibility
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@apiclient.xyz/docker',
|
||||
version: '5.1.1',
|
||||
version: '5.1.2',
|
||||
description: 'Provides easy communication with Docker remote API from Node.js, with TypeScript support.'
|
||||
}
|
||||
|
||||
@@ -62,7 +62,11 @@ export class DockerContainer extends DockerResource {
|
||||
if (response.statusCode < 300) {
|
||||
logger.log('info', 'Container created successfully');
|
||||
// Return the created container instance
|
||||
return await DockerContainer._fromId(dockerHost, response.body.Id);
|
||||
const container = await DockerContainer._fromId(dockerHost, response.body.Id);
|
||||
if (!container) {
|
||||
throw new Error('Container was created but could not be retrieved');
|
||||
}
|
||||
return container;
|
||||
} else {
|
||||
logger.log('error', 'There has been a problem when creating the container');
|
||||
throw new Error(`Failed to create container: ${response.statusCode}`);
|
||||
@@ -70,18 +74,18 @@ export class DockerContainer extends DockerResource {
|
||||
}
|
||||
|
||||
// INSTANCE PROPERTIES
|
||||
public Id: string;
|
||||
public Names: string[];
|
||||
public Image: string;
|
||||
public ImageID: string;
|
||||
public Command: string;
|
||||
public Created: number;
|
||||
public Ports: interfaces.TPorts;
|
||||
public Labels: interfaces.TLabels;
|
||||
public State: string;
|
||||
public Status: string;
|
||||
public Id!: string;
|
||||
public Names!: string[];
|
||||
public Image!: string;
|
||||
public ImageID!: string;
|
||||
public Command!: string;
|
||||
public Created!: number;
|
||||
public Ports!: interfaces.TPorts;
|
||||
public Labels!: interfaces.TLabels;
|
||||
public State!: string;
|
||||
public Status!: string;
|
||||
public HostConfig: any;
|
||||
public NetworkSettings: {
|
||||
public NetworkSettings!: {
|
||||
Networks: {
|
||||
[key: string]: {
|
||||
IPAMConfig: any;
|
||||
|
||||
@@ -29,7 +29,7 @@ export class DockerHost {
|
||||
public socketPath: string;
|
||||
private registryToken: string = '';
|
||||
private imageStore: DockerImageStore; // Now private - use storeImage/retrieveImage instead
|
||||
public smartBucket: plugins.smartbucket.SmartBucket;
|
||||
public smartBucket!: plugins.smartbucket.SmartBucket;
|
||||
|
||||
/**
|
||||
* the constructor to instantiate a new docker sock instance
|
||||
@@ -64,8 +64,8 @@ export class DockerHost {
|
||||
console.log(`using docker sock at ${pathToUse}`);
|
||||
this.socketPath = pathToUse;
|
||||
this.imageStore = new DockerImageStore({
|
||||
bucketDir: null,
|
||||
localDirPath: this.options.imageStoreDir,
|
||||
bucketDir: null!,
|
||||
localDirPath: this.options.imageStoreDir!,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,6 +74,9 @@ export class DockerHost {
|
||||
}
|
||||
public async stop() {
|
||||
await this.imageStore.stop();
|
||||
if (this.smartBucket) {
|
||||
this.smartBucket.storageClient.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +134,7 @@ export class DockerHost {
|
||||
const dockerConfigPath = plugins.smartpath.get.home(
|
||||
'~/.docker/config.json',
|
||||
);
|
||||
const configObject = plugins.smartfile.fs.toObjectSync(dockerConfigPath);
|
||||
const configObject = JSON.parse(plugins.fs.readFileSync(dockerConfigPath, 'utf8'));
|
||||
const gitlabAuthBase64 = configObject.auths[registryUrlArg].auth;
|
||||
const gitlabAuth: string =
|
||||
plugins.smartstring.base64.decode(gitlabAuthBase64);
|
||||
@@ -379,8 +382,14 @@ export class DockerHost {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
nodeStream.on('error', (err) => {
|
||||
// Connection resets are expected when the stream is destroyed
|
||||
if ((err as any).code !== 'ECONNRESET') {
|
||||
observer.error(err);
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
nodeStream.emit('end');
|
||||
nodeStream.destroy();
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -390,14 +399,19 @@ export class DockerHost {
|
||||
*/
|
||||
public async activateSwarm(addvertisementIpArg?: string) {
|
||||
// determine advertisement address
|
||||
let addvertisementIp: string;
|
||||
let addvertisementIp: string = '';
|
||||
if (addvertisementIpArg) {
|
||||
addvertisementIp = addvertisementIpArg;
|
||||
} else {
|
||||
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
|
||||
const defaultGateway = await smartnetworkInstance.getDefaultGateway();
|
||||
if (defaultGateway) {
|
||||
addvertisementIp = defaultGateway.ipv4.address;
|
||||
try {
|
||||
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
|
||||
const defaultGateway = await smartnetworkInstance.getDefaultGateway();
|
||||
if (defaultGateway) {
|
||||
addvertisementIp = defaultGateway.ipv4.address;
|
||||
}
|
||||
} catch (err) {
|
||||
// Failed to determine default gateway (e.g. in Deno without --allow-run)
|
||||
// Docker will auto-detect the advertise address
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +516,7 @@ export class DockerHost {
|
||||
routeArg: string,
|
||||
readStream?: plugins.smartstream.stream.Readable,
|
||||
jsonData?: any,
|
||||
) {
|
||||
): Promise<plugins.smartstream.stream.Readable | { statusCode: number; body: string; headers: any }> {
|
||||
const requestUrl = `${this.socketPath}${routeArg}`;
|
||||
|
||||
// Build the request using the fluent API
|
||||
@@ -579,6 +593,10 @@ export class DockerHost {
|
||||
// Convert web ReadableStream to Node.js stream for backward compatibility
|
||||
const nodeStream = plugins.smartstream.nodewebhelpers.convertWebReadableToNodeReadable(webStream);
|
||||
|
||||
// Add a default error handler to prevent unhandled 'error' events from crashing the process.
|
||||
// Callers that attach their own 'error' listener will still receive the event.
|
||||
nodeStream.on('error', () => {});
|
||||
|
||||
// Add properties for compatibility
|
||||
(nodeStream as any).statusCode = response.status;
|
||||
(nodeStream as any).body = ''; // For compatibility
|
||||
|
||||
@@ -59,8 +59,8 @@ export class DockerImage extends DockerResource {
|
||||
imageOriginTag: string;
|
||||
} = {
|
||||
imageUrl: optionsArg.creationObject.imageUrl,
|
||||
imageTag: optionsArg.creationObject.imageTag,
|
||||
imageOriginTag: null,
|
||||
imageTag: optionsArg.creationObject.imageTag ?? '',
|
||||
imageOriginTag: '',
|
||||
};
|
||||
if (imageUrlObject.imageUrl.includes(':')) {
|
||||
const imageUrl = imageUrlObject.imageUrl.split(':')[0];
|
||||
@@ -94,9 +94,24 @@ export class DockerImage extends DockerResource {
|
||||
dockerHostArg,
|
||||
imageUrlObject.imageOriginTag,
|
||||
);
|
||||
if (!image) {
|
||||
throw new Error(`Image ${imageUrlObject.imageOriginTag} not found after pull`);
|
||||
}
|
||||
return image;
|
||||
} else {
|
||||
logger.log('error', `Failed at the attempt of creating a new image`);
|
||||
// Pull failed — check if the image already exists locally
|
||||
const existingImage = await DockerImage._fromName(
|
||||
dockerHostArg,
|
||||
imageUrlObject.imageOriginTag,
|
||||
);
|
||||
if (existingImage) {
|
||||
logger.log(
|
||||
'warn',
|
||||
`Pull failed for ${imageUrlObject.imageUrl}, using locally cached image`,
|
||||
);
|
||||
return existingImage;
|
||||
}
|
||||
throw new Error(`Failed to pull image ${imageUrlObject.imageOriginTag} and no local copy exists`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,16 +232,16 @@ export class DockerImage extends DockerResource {
|
||||
/**
|
||||
* the tags for an image
|
||||
*/
|
||||
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;
|
||||
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: DockerHost, dockerImageObjectArg: any) {
|
||||
super(dockerHostArg);
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as paths from './paths.js';
|
||||
import { logger } from './logger.js';
|
||||
import type { DockerHost } from './classes.host.js';
|
||||
|
||||
const smartfileFactory = plugins.smartfile.SmartFileFactory.nodeFs();
|
||||
|
||||
export interface IDockerImageStoreConstructorOptions {
|
||||
/**
|
||||
* used for preparing images for longer term storage
|
||||
@@ -38,14 +40,12 @@ export class DockerImageStore {
|
||||
uniqueProcessingId,
|
||||
);
|
||||
// Create a write stream to store the tar file
|
||||
const writeStream = plugins.smartfile.fsStream.createWriteStream(
|
||||
initialTarDownloadPath,
|
||||
);
|
||||
const writeStream = plugins.fs.createWriteStream(initialTarDownloadPath);
|
||||
|
||||
// lets wait for the write stream to finish
|
||||
await new Promise((resolve, reject) => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
tarStream.pipe(writeStream);
|
||||
writeStream.on('finish', resolve);
|
||||
writeStream.on('finish', () => resolve());
|
||||
writeStream.on('error', reject);
|
||||
});
|
||||
logger.log(
|
||||
@@ -54,44 +54,55 @@ export class DockerImageStore {
|
||||
);
|
||||
|
||||
// lets process the image
|
||||
const tarArchive = await plugins.smartarchive.SmartArchive.fromArchiveFile(
|
||||
initialTarDownloadPath,
|
||||
);
|
||||
await tarArchive.exportToFs(extractionDir);
|
||||
await plugins.smartarchive.SmartArchive.create()
|
||||
.file(initialTarDownloadPath)
|
||||
.extract(extractionDir);
|
||||
logger.log('info', `Image ${imageName} extracted.`);
|
||||
await plugins.smartfile.fs.remove(initialTarDownloadPath);
|
||||
await plugins.fs.promises.rm(initialTarDownloadPath, { force: true });
|
||||
logger.log('info', `deleted original tar to save space.`);
|
||||
logger.log('info', `now repackaging for s3...`);
|
||||
const smartfileIndexJson = await plugins.smartfile.SmartFile.fromFilePath(
|
||||
const smartfileIndexJson = await smartfileFactory.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'index.json'),
|
||||
);
|
||||
const smartfileManifestJson =
|
||||
await plugins.smartfile.SmartFile.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'manifest.json'),
|
||||
);
|
||||
const smartfileOciLayoutJson =
|
||||
await plugins.smartfile.SmartFile.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'oci-layout'),
|
||||
);
|
||||
const smartfileRepositoriesJson =
|
||||
await plugins.smartfile.SmartFile.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'repositories'),
|
||||
);
|
||||
const smartfileManifestJson = await smartfileFactory.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'manifest.json'),
|
||||
);
|
||||
const smartfileOciLayoutJson = await smartfileFactory.fromFilePath(
|
||||
plugins.path.join(extractionDir, 'oci-layout'),
|
||||
);
|
||||
|
||||
// repositories file is optional in OCI image tars
|
||||
const repositoriesPath = plugins.path.join(extractionDir, 'repositories');
|
||||
const hasRepositories = plugins.fs.existsSync(repositoriesPath);
|
||||
const smartfileRepositoriesJson = hasRepositories
|
||||
? await smartfileFactory.fromFilePath(repositoriesPath)
|
||||
: null;
|
||||
|
||||
const indexJson = JSON.parse(smartfileIndexJson.contents.toString());
|
||||
const manifestJson = JSON.parse(smartfileManifestJson.contents.toString());
|
||||
const ociLayoutJson = JSON.parse(
|
||||
smartfileOciLayoutJson.contents.toString(),
|
||||
);
|
||||
const repositoriesJson = JSON.parse(
|
||||
smartfileRepositoriesJson.contents.toString(),
|
||||
);
|
||||
|
||||
indexJson.manifests[0].annotations['io.containerd.image.name'] = imageName;
|
||||
manifestJson[0].RepoTags[0] = imageName;
|
||||
const repoFirstKey = Object.keys(repositoriesJson)[0];
|
||||
const repoFirstValue = repositoriesJson[repoFirstKey];
|
||||
repositoriesJson[imageName] = repoFirstValue;
|
||||
delete repositoriesJson[repoFirstKey];
|
||||
if (indexJson.manifests?.[0]?.annotations) {
|
||||
indexJson.manifests[0].annotations['io.containerd.image.name'] = imageName;
|
||||
}
|
||||
if (manifestJson?.[0]?.RepoTags) {
|
||||
manifestJson[0].RepoTags[0] = imageName;
|
||||
}
|
||||
|
||||
if (smartfileRepositoriesJson) {
|
||||
const repositoriesJson = JSON.parse(
|
||||
smartfileRepositoriesJson.contents.toString(),
|
||||
);
|
||||
const repoFirstKey = Object.keys(repositoriesJson)[0];
|
||||
const repoFirstValue = repositoriesJson[repoFirstKey];
|
||||
repositoriesJson[imageName] = repoFirstValue;
|
||||
delete repositoriesJson[repoFirstKey];
|
||||
smartfileRepositoriesJson.contents = Buffer.from(
|
||||
JSON.stringify(repositoriesJson, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
smartfileIndexJson.contents = Buffer.from(
|
||||
JSON.stringify(indexJson, null, 2),
|
||||
@@ -102,45 +113,51 @@ export class DockerImageStore {
|
||||
smartfileOciLayoutJson.contents = Buffer.from(
|
||||
JSON.stringify(ociLayoutJson, null, 2),
|
||||
);
|
||||
smartfileRepositoriesJson.contents = Buffer.from(
|
||||
JSON.stringify(repositoriesJson, null, 2),
|
||||
);
|
||||
await Promise.all([
|
||||
|
||||
const writePromises = [
|
||||
smartfileIndexJson.write(),
|
||||
smartfileManifestJson.write(),
|
||||
smartfileOciLayoutJson.write(),
|
||||
smartfileRepositoriesJson.write(),
|
||||
]);
|
||||
];
|
||||
if (smartfileRepositoriesJson) {
|
||||
writePromises.push(smartfileRepositoriesJson.write());
|
||||
}
|
||||
await Promise.all(writePromises);
|
||||
|
||||
logger.log('info', 'repackaging archive for s3...');
|
||||
const tartools = new plugins.smartarchive.TarTools();
|
||||
const newTarPack = await tartools.packDirectory(extractionDir);
|
||||
const newTarPack = await tartools.getDirectoryPackStream(extractionDir);
|
||||
const finalTarName = `${uniqueProcessingId}.processed.tar`;
|
||||
const finalTarPath = plugins.path.join(
|
||||
this.options.localDirPath,
|
||||
finalTarName,
|
||||
);
|
||||
const finalWriteStream =
|
||||
plugins.smartfile.fsStream.createWriteStream(finalTarPath);
|
||||
await new Promise((resolve, reject) => {
|
||||
newTarPack.finalize();
|
||||
const finalWriteStream = plugins.fs.createWriteStream(finalTarPath);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
newTarPack.pipe(finalWriteStream);
|
||||
finalWriteStream.on('finish', resolve);
|
||||
finalWriteStream.on('finish', () => resolve());
|
||||
finalWriteStream.on('error', reject);
|
||||
});
|
||||
logger.log('ok', `Repackaged image ${imageName} for s3.`);
|
||||
await plugins.smartfile.fs.remove(extractionDir);
|
||||
const finalTarReadStream =
|
||||
plugins.smartfile.fsStream.createReadStream(finalTarPath);
|
||||
await plugins.fs.promises.rm(extractionDir, { recursive: true, force: true });
|
||||
// Remove existing file in bucket if it exists (smartbucket v4 no longer silently overwrites)
|
||||
try {
|
||||
await this.options.bucketDir.fastRemove({ path: `${imageName}.tar` });
|
||||
} catch (e) {
|
||||
// File may not exist, which is fine
|
||||
}
|
||||
const finalTarReadStream = plugins.fs.createReadStream(finalTarPath);
|
||||
await this.options.bucketDir.fastPutStream({
|
||||
stream: finalTarReadStream,
|
||||
path: `${imageName}.tar`,
|
||||
});
|
||||
await plugins.smartfile.fs.remove(finalTarPath);
|
||||
await plugins.fs.promises.rm(finalTarPath, { force: true });
|
||||
}
|
||||
|
||||
public async start() {
|
||||
await plugins.smartfile.fs.ensureEmptyDir(this.options.localDirPath);
|
||||
// Ensure the local directory exists and is empty
|
||||
await plugins.fs.promises.rm(this.options.localDirPath, { recursive: true, force: true });
|
||||
await plugins.fs.promises.mkdir(this.options.localDirPath, { recursive: true });
|
||||
}
|
||||
|
||||
public async stop() {}
|
||||
@@ -154,10 +171,10 @@ export class DockerImageStore {
|
||||
`${imageName}.tar`,
|
||||
);
|
||||
|
||||
if (!(await plugins.smartfile.fs.fileExists(imagePath))) {
|
||||
if (!plugins.fs.existsSync(imagePath)) {
|
||||
throw new Error(`Image ${imageName} does not exist.`);
|
||||
}
|
||||
|
||||
return plugins.smartfile.fsStream.createReadStream(imagePath);
|
||||
return plugins.fs.createReadStream(imagePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,30 +61,30 @@ export class DockerNetwork extends DockerResource {
|
||||
});
|
||||
if (response.statusCode < 300) {
|
||||
logger.log('info', 'Created network successfully');
|
||||
return await DockerNetwork._fromName(
|
||||
const network = await DockerNetwork._fromName(
|
||||
dockerHost,
|
||||
networkCreationDescriptor.Name,
|
||||
);
|
||||
if (!network) {
|
||||
throw new Error('Network was created but could not be retrieved');
|
||||
}
|
||||
return network;
|
||||
} else {
|
||||
logger.log(
|
||||
'error',
|
||||
'There has been an error creating the wanted network',
|
||||
);
|
||||
return null;
|
||||
throw new Error('There has been an error creating the wanted network');
|
||||
}
|
||||
}
|
||||
|
||||
// INSTANCE PROPERTIES
|
||||
public Name: string;
|
||||
public Id: string;
|
||||
public Created: string;
|
||||
public Scope: string;
|
||||
public Driver: string;
|
||||
public EnableIPv6: boolean;
|
||||
public Internal: boolean;
|
||||
public Attachable: boolean;
|
||||
public Ingress: false;
|
||||
public IPAM: {
|
||||
public Name!: string;
|
||||
public Id!: string;
|
||||
public Created!: string;
|
||||
public Scope!: string;
|
||||
public Driver!: string;
|
||||
public EnableIPv6!: boolean;
|
||||
public Internal!: boolean;
|
||||
public Attachable!: boolean;
|
||||
public Ingress!: false;
|
||||
public IPAM!: {
|
||||
Driver: 'default' | 'bridge' | 'overlay';
|
||||
Config: [
|
||||
{
|
||||
@@ -130,7 +130,7 @@ export class DockerNetwork extends DockerResource {
|
||||
IPv6Address: string;
|
||||
}>
|
||||
> {
|
||||
const returnArray = [];
|
||||
const returnArray: any[] = [];
|
||||
const response = await this.dockerHost.request(
|
||||
'GET',
|
||||
`/networks/${this.Id}`,
|
||||
|
||||
@@ -72,12 +72,12 @@ export class DockerSecret extends DockerResource {
|
||||
}
|
||||
|
||||
// INSTANCE PROPERTIES
|
||||
public ID: string;
|
||||
public Spec: {
|
||||
public ID!: string;
|
||||
public Spec!: {
|
||||
Name: string;
|
||||
Labels: interfaces.TLabels;
|
||||
};
|
||||
public Version: {
|
||||
public Version!: {
|
||||
Index: string;
|
||||
};
|
||||
|
||||
@@ -101,7 +101,6 @@ export class DockerSecret extends DockerResource {
|
||||
* Updates a secret
|
||||
*/
|
||||
public async update(contentArg: string) {
|
||||
const route = `/secrets/${this.ID}/update?=version=${this.Version.Index}`;
|
||||
const response = await this.dockerHost.request(
|
||||
'POST',
|
||||
`/secrets/${this.ID}/update?version=${this.Version.Index}`,
|
||||
|
||||
@@ -37,6 +37,9 @@ export class DockerService extends DockerResource {
|
||||
const wantedService = allServices.find((service) => {
|
||||
return service.Spec.Name === networkName;
|
||||
});
|
||||
if (!wantedService) {
|
||||
throw new Error(`Service not found: ${networkName}`);
|
||||
}
|
||||
return wantedService;
|
||||
}
|
||||
|
||||
@@ -56,10 +59,11 @@ export class DockerService extends DockerResource {
|
||||
// Resolve image (support both string and DockerImage instance)
|
||||
let imageInstance: DockerImage;
|
||||
if (typeof serviceCreationDescriptor.image === 'string') {
|
||||
imageInstance = await DockerImage._fromName(dockerHost, serviceCreationDescriptor.image);
|
||||
if (!imageInstance) {
|
||||
const foundImage = await DockerImage._fromName(dockerHost, serviceCreationDescriptor.image);
|
||||
if (!foundImage) {
|
||||
throw new Error(`Image not found: ${serviceCreationDescriptor.image}`);
|
||||
}
|
||||
imageInstance = foundImage;
|
||||
} else {
|
||||
imageInstance = serviceCreationDescriptor.image;
|
||||
}
|
||||
@@ -131,7 +135,7 @@ export class DockerService extends DockerResource {
|
||||
});
|
||||
}
|
||||
|
||||
const ports = [];
|
||||
const ports: Array<{ Protocol: string; PublishedPort: number; TargetPort: number }> = [];
|
||||
for (const port of serviceCreationDescriptor.ports) {
|
||||
const portArray = port.split(':');
|
||||
const hostPort = portArray[0];
|
||||
@@ -149,10 +153,11 @@ export class DockerService extends DockerResource {
|
||||
// Resolve secret instance
|
||||
let secretInstance: DockerSecret;
|
||||
if (typeof secret === 'string') {
|
||||
secretInstance = await DockerSecret._fromName(dockerHost, secret);
|
||||
if (!secretInstance) {
|
||||
const foundSecret = await DockerSecret._fromName(dockerHost, secret);
|
||||
if (!foundSecret) {
|
||||
throw new Error(`Secret not found: ${secret}`);
|
||||
}
|
||||
secretInstance = foundSecret;
|
||||
} else {
|
||||
secretInstance = secret;
|
||||
}
|
||||
@@ -171,21 +176,12 @@ export class DockerService extends DockerResource {
|
||||
|
||||
// lets configure limits
|
||||
|
||||
const memoryLimitMB =
|
||||
serviceCreationDescriptor.resources &&
|
||||
serviceCreationDescriptor.resources.memorySizeMB
|
||||
? serviceCreationDescriptor.resources.memorySizeMB
|
||||
: 1000;
|
||||
const memoryLimitMB = serviceCreationDescriptor.resources?.memorySizeMB ?? 1000;
|
||||
|
||||
const limits = {
|
||||
MemoryBytes: memoryLimitMB * 1000000,
|
||||
};
|
||||
|
||||
if (serviceCreationDescriptor.resources) {
|
||||
limits.MemoryBytes =
|
||||
serviceCreationDescriptor.resources.memorySizeMB * 1000000;
|
||||
}
|
||||
|
||||
const response = await dockerHost.request('POST', '/services/create', {
|
||||
Name: serviceCreationDescriptor.name,
|
||||
TaskTemplate: {
|
||||
@@ -234,11 +230,11 @@ export class DockerService extends DockerResource {
|
||||
// INSTANCE PROPERTIES
|
||||
// Note: dockerHost (not dockerHostRef) for consistency with base class
|
||||
|
||||
public ID: string;
|
||||
public Version: { Index: number };
|
||||
public CreatedAt: string;
|
||||
public UpdatedAt: string;
|
||||
public Spec: {
|
||||
public ID!: string;
|
||||
public Version!: { Index: number };
|
||||
public CreatedAt!: string;
|
||||
public UpdatedAt!: string;
|
||||
public Spec!: {
|
||||
Name: string;
|
||||
Labels: interfaces.TLabels;
|
||||
TaskTemplate: {
|
||||
@@ -261,7 +257,7 @@ export class DockerService extends DockerResource {
|
||||
Mode: {};
|
||||
Networks: [any[]];
|
||||
};
|
||||
public Endpoint: { Spec: {}; VirtualIPs: [any[]] };
|
||||
public Endpoint!: { Spec: {}; VirtualIPs: [any[]] };
|
||||
|
||||
constructor(dockerHostArg: DockerHost) {
|
||||
super(dockerHostArg);
|
||||
@@ -325,6 +321,7 @@ export class DockerService extends DockerResource {
|
||||
return true;
|
||||
} else {
|
||||
console.log(`service ${this.Spec.Name} is up to date.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// node native path
|
||||
// node native
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export { path };
|
||||
export { fs, path };
|
||||
|
||||
// @pushrocks scope
|
||||
import * as lik from '@push.rocks/lik';
|
||||
import * as smartarchive from '@push.rocks/smartarchive';
|
||||
import * as smartbucket from '@push.rocks/smartbucket';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
|
||||
import * as smartjson from '@push.rocks/smartjson';
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import * as smartnetwork from '@push.rocks/smartnetwork';
|
||||
@@ -24,6 +26,7 @@ export {
|
||||
smartarchive,
|
||||
smartbucket,
|
||||
smartfile,
|
||||
|
||||
smartjson,
|
||||
smartlog,
|
||||
smartnetwork,
|
||||
|
||||
Reference in New Issue
Block a user