218 lines
6.2 KiB
TypeScript
218 lines
6.2 KiB
TypeScript
import * as plugins from './plugins.js';
|
|
import { DockerContainer } from './classes.container.js';
|
|
import { DockerNetwork } from './classes.network.js';
|
|
import { DockerService } from './classes.service.js';
|
|
import { logger } from './logging.js';
|
|
import path from 'path';
|
|
import type { DockerImageStore } from './classes.imagestore.js';
|
|
|
|
export interface IAuthData {
|
|
serveraddress: string;
|
|
username: string;
|
|
password: string;
|
|
}
|
|
|
|
export interface IDockerHostConstructorOptions {
|
|
dockerSockPath?: string;
|
|
imageStoreDir?: string;
|
|
}
|
|
|
|
export class DockerHost {
|
|
/**
|
|
* the path where the docker sock can be found
|
|
*/
|
|
public socketPath: string;
|
|
private registryToken: string = '';
|
|
public imageStore: DockerImageStore;
|
|
|
|
/**
|
|
* the constructor to instantiate a new docker sock instance
|
|
* @param pathArg
|
|
*/
|
|
constructor(optionsArg: IDockerHostConstructorOptions) {
|
|
let pathToUse: string;
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* authenticate against a registry
|
|
* @param userArg
|
|
* @param passArg
|
|
*/
|
|
public async auth(authData: IAuthData) {
|
|
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
|
|
*/
|
|
public async getAuthTokenFromDockerConfig(registryUrlArg: string) {
|
|
const dockerConfigPath = plugins.smartpath.get.home('~/.docker/config.json');
|
|
const configObject = plugins.smartfile.fs.toObjectSync(dockerConfigPath);
|
|
const gitlabAuthBase64 = configObject.auths[registryUrlArg].auth;
|
|
const gitlabAuth: string = plugins.smartstring.base64.decode(gitlabAuthBase64);
|
|
const gitlabAuthArray = gitlabAuth.split(':');
|
|
await this.auth({
|
|
username: gitlabAuthArray[0],
|
|
password: gitlabAuthArray[1],
|
|
serveraddress: registryUrlArg,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* gets all networks
|
|
*/
|
|
public async getNetworks() {
|
|
return await DockerNetwork.getNetworks(this);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* gets all containers
|
|
*/
|
|
public async getContainers() {
|
|
const containerArray = await DockerContainer.getContainers(this);
|
|
return containerArray;
|
|
}
|
|
|
|
/**
|
|
* gets all services
|
|
*/
|
|
public async getServices() {
|
|
const serviceArray = await DockerService.getServices(this);
|
|
return serviceArray;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public async getEventObservable(): Promise<plugins.rxjs.Observable<any>> {
|
|
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
|
|
*/
|
|
public async activateSwarm(addvertisementIpArg?: string) {
|
|
// determine advertisement address
|
|
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;
|
|
}
|
|
}
|
|
|
|
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
|
|
*/
|
|
public async request(methodArg: string, routeArg: string, 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;
|
|
}
|
|
|
|
public async requestStreaming(methodArg: string, routeArg: string, readStream?: plugins.smartstream.stream.Readable) {
|
|
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;
|
|
}
|
|
}
|