@apiclient.xyz/docker
Version:
Provides easy communication with Docker remote API from Node.js, with TypeScript support.
257 lines • 17.9 kB
JavaScript
import * as plugins from './plugins.js';
import * as paths from './paths.js';
import { DockerContainer } from './classes.container.js';
import { DockerNetwork } from './classes.network.js';
import { DockerService } from './classes.service.js';
import { logger } from './logger.js';
import path from 'path';
import { DockerImageStore } from './classes.imagestore.js';
import { DockerImage } from './classes.image.js';
export class DockerHost {
/**
* the constructor to instantiate a new docker sock instance
* @param pathArg
*/
constructor(optionsArg) {
this.registryToken = '';
this.options = {
...{
imageStoreDir: plugins.path.join(paths.nogitDir, 'temp-docker-image-store'),
},
...optionsArg,
};
let pathToUse;
if (optionsArg.dockerSockPath) {
pathToUse = optionsArg.dockerSockPath;
}
else if (process.env.DOCKER_HOST) {
pathToUse = process.env.DOCKER_HOST;
}
else if (process.env.CI) {
pathToUse = 'http://docker:2375/';
}
else {
pathToUse = 'http://unix:/var/run/docker.sock:';
}
if (pathToUse.startsWith('unix:///')) {
pathToUse = pathToUse.replace('unix://', 'http://unix:');
}
if (pathToUse.endsWith('.sock')) {
pathToUse = pathToUse.replace('.sock', '.sock:');
}
console.log(`using docker sock at ${pathToUse}`);
this.socketPath = pathToUse;
this.imageStore = new DockerImageStore({
bucketDir: null,
localDirPath: this.options.imageStoreDir,
});
}
async start() {
await this.imageStore.start();
}
async stop() {
await this.imageStore.stop();
}
/**
* authenticate against a registry
* @param userArg
* @param passArg
*/
async auth(authData) {
const response = await this.request('POST', '/auth', authData);
if (response.body.Status !== 'Login Succeeded') {
console.log(`Login failed with ${response.body.Status}`);
throw new Error(response.body.Status);
}
console.log(response.body.Status);
this.registryToken = plugins.smartstring.base64.encode(plugins.smartjson.stringify(authData));
}
/**
* gets the token from the .docker/config.json file for GitLab registry
*/
async getAuthTokenFromDockerConfig(registryUrlArg) {
const dockerConfigPath = plugins.smartpath.get.home('~/.docker/config.json');
const configObject = plugins.smartfile.fs.toObjectSync(dockerConfigPath);
const gitlabAuthBase64 = configObject.auths[registryUrlArg].auth;
const gitlabAuth = plugins.smartstring.base64.decode(gitlabAuthBase64);
const gitlabAuthArray = gitlabAuth.split(':');
await this.auth({
username: gitlabAuthArray[0],
password: gitlabAuthArray[1],
serveraddress: registryUrlArg,
});
}
// ==============
// NETWORKS
// ==============
/**
* gets all networks
*/
async getNetworks() {
return await DockerNetwork.getNetworks(this);
}
/**
* create a network
*/
async createNetwork(optionsArg) {
return await DockerNetwork.createNetwork(this, optionsArg);
}
/**
* get a network by name
*/
async getNetworkByName(networkNameArg) {
return await DockerNetwork.getNetworkByName(this, networkNameArg);
}
// ==============
// CONTAINERS
// ==============
/**
* gets all containers
*/
async getContainers() {
const containerArray = await DockerContainer.getContainers(this);
return containerArray;
}
// ==============
// SERVICES
// ==============
/**
* gets all services
*/
async getServices() {
const serviceArray = await DockerService.getServices(this);
return serviceArray;
}
// ==============
// IMAGES
// ==============
/**
* get all images
*/
async getImages() {
return await DockerImage.getImages(this);
}
/**
* get an image by name
*/
async getImageByName(imageNameArg) {
return await DockerImage.getImageByName(this, imageNameArg);
}
/**
*
*/
async getEventObservable() {
const response = await this.requestStreaming('GET', '/events');
return plugins.rxjs.Observable.create((observer) => {
response.on('data', (data) => {
const eventString = data.toString();
try {
const eventObject = JSON.parse(eventString);
observer.next(eventObject);
}
catch (e) {
console.log(e);
}
});
return () => {
response.emit('end');
};
});
}
/**
* activates docker swarm
*/
async activateSwarm(addvertisementIpArg) {
// determine advertisement address
let addvertisementIp;
if (addvertisementIpArg) {
addvertisementIp = addvertisementIpArg;
}
else {
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
const defaultGateway = await smartnetworkInstance.getDefaultGateway();
if (defaultGateway) {
addvertisementIp = defaultGateway.ipv4.address;
}
}
const response = await this.request('POST', '/swarm/init', {
ListenAddr: '0.0.0.0:2377',
AdvertiseAddr: addvertisementIp,
DataPathPort: 4789,
DefaultAddrPool: ['10.10.0.0/8', '20.20.0.0/8'],
SubnetSize: 24,
ForceNewCluster: false,
});
if (response.statusCode === 200) {
logger.log('info', 'created Swam succesfully');
}
else {
logger.log('error', 'could not initiate swarm');
}
}
/**
* fire a request
*/
async request(methodArg, routeArg, dataArg = {}) {
const requestUrl = `${this.socketPath}${routeArg}`;
const response = await plugins.smartrequest.request(requestUrl, {
method: methodArg,
headers: {
'Content-Type': 'application/json',
'X-Registry-Auth': this.registryToken,
Host: 'docker.sock',
},
requestBody: dataArg,
keepAlive: false,
});
if (response.statusCode !== 200) {
console.log(response.body);
}
return response;
}
async requestStreaming(methodArg, routeArg, readStream) {
const requestUrl = `${this.socketPath}${routeArg}`;
const response = await plugins.smartrequest.request(requestUrl, {
method: methodArg,
headers: {
'Content-Type': 'application/json',
'X-Registry-Auth': this.registryToken,
Host: 'docker.sock',
},
requestBody: null,
keepAlive: false,
}, true, (readStream ? reqArg => {
let counter = 0;
const smartduplex = new plugins.smartstream.SmartDuplex({
writeFunction: async (chunkArg) => {
if (counter % 1000 === 0) {
console.log(`posting chunk ${counter}`);
}
counter++;
return chunkArg;
}
});
readStream.pipe(smartduplex).pipe(reqArg);
} : null));
console.log(response.statusCode);
console.log(response.body);
return response;
}
/**
* add s3 storage
* @param optionsArg
*/
async addS3Storage(optionsArg) {
this.smartBucket = new plugins.smartbucket.SmartBucket(optionsArg);
if (!optionsArg.bucketName) {
throw new Error('bucketName is required');
}
const bucket = await this.smartBucket.getBucketByName(optionsArg.bucketName);
let wantedDirectory = await bucket.getBaseDirectory();
if (optionsArg.directoryPath) {
wantedDirectory = await wantedDirectory.getSubDirectoryByName(optionsArg.directoryPath);
}
this.imageStore.options.bucketDir = wantedDirectory;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5ob3N0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5ob3N0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxLQUFLLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDckQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzNELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQWFqRCxNQUFNLE9BQU8sVUFBVTtJQVdyQjs7O09BR0c7SUFDSCxZQUFZLFVBQXlDO1FBUjdDLGtCQUFhLEdBQVcsRUFBRSxDQUFDO1FBU2pDLElBQUksQ0FBQyxPQUFPLEdBQUc7WUFDYixHQUFHO2dCQUNELGFBQWEsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLHlCQUF5QixDQUFDO2FBQzVFO1lBQ0QsR0FBRyxVQUFVO1NBQ2QsQ0FBQTtRQUNELElBQUksU0FBaUIsQ0FBQztRQUN0QixJQUFJLFVBQVUsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUM5QixTQUFTLEdBQUcsVUFBVSxDQUFDLGNBQWMsQ0FBQztRQUN4QyxDQUFDO2FBQU0sSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25DLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQztRQUN0QyxDQUFD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