Compare commits
No commits in common. "384f6c9b4ac95b447b571de9535efb8c1b74169b" and "eb38d1402ed27e55a4933417ee17a3c5ce1e052c" have entirely different histories.
384f6c9b4a
...
eb38d1402e
|
|
@ -1,3 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
dist
|
|
||||||
12
Dockerfile
12
Dockerfile
|
|
@ -1,11 +1,19 @@
|
||||||
FROM node:lts-alpine3.17
|
FROM archlinux:latest
|
||||||
|
|
||||||
|
RUN pacman -Syu --noconfirm
|
||||||
|
RUN pacman -S --noconfirm nodejs npm
|
||||||
|
RUN node --version
|
||||||
|
RUN npm --version
|
||||||
|
RUN npm install -g npm yarn
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./dist /app
|
COPY ./dist /app
|
||||||
COPY ./package.json /app/package.json
|
COPY ./package.json /app/package.json
|
||||||
COPY ./node_modules /app/node_modules
|
COPY ./node_modules /app/node_modules
|
||||||
|
|
||||||
EXPOSE 42069
|
RUN find /app
|
||||||
|
|
||||||
|
EXPOSE 6969
|
||||||
|
|
||||||
CMD node /app/main.js
|
CMD node /app/main.js
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { buildDockerImage, createContainer } from "../apis/docker.js";
|
||||||
|
import { createCertificate, createProxyHost, deleteProxyHostByDomain, getCertificateByDomains, hasCerficateByDomains, isDomainRegistered } from "../apis/npm.js";
|
||||||
|
import { BASE_DOMAIN, INTERNAL_ADDRESS } from "../config.js";
|
||||||
|
export default async function deploy(options) {
|
||||||
|
const { cloneUrl, branch } = options;
|
||||||
|
const [, user, name] = /http[s]{0,1}:\/\/.*\/(.*)\/(.*)\.git/.exec(cloneUrl);
|
||||||
|
console.log(`deploying ${user}/${name}`);
|
||||||
|
const imageName = await buildDockerImage({
|
||||||
|
user,
|
||||||
|
name,
|
||||||
|
cloneUrl,
|
||||||
|
branch
|
||||||
|
});
|
||||||
|
const containerName = `deploy-${user}-${name}-${branch}`;
|
||||||
|
const { port } = await createContainer(imageName, containerName);
|
||||||
|
const domain = `${branch}.${name}.${user}.${BASE_DOMAIN}`;
|
||||||
|
await ensureDomainConfig(domain, port);
|
||||||
|
console.log(`${user}/${name} available at https://${domain}/`);
|
||||||
|
}
|
||||||
|
async function ensureDomainConfig(domain, port) {
|
||||||
|
// === certificate info
|
||||||
|
let certId = null;
|
||||||
|
if (await hasCerficateByDomains([domain])) {
|
||||||
|
certId = (await getCertificateByDomains([domain])).id;
|
||||||
|
console.log('certificate for', domain, 'already exists');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const newCert = await createCertificate([domain]);
|
||||||
|
certId = newCert.id;
|
||||||
|
}
|
||||||
|
if (await isDomainRegistered(domain)) {
|
||||||
|
await deleteProxyHostByDomain(domain);
|
||||||
|
}
|
||||||
|
await createProxyHost([domain], port, INTERNAL_ADDRESS, {
|
||||||
|
ssl_forced: true,
|
||||||
|
block_exploits: true,
|
||||||
|
allow_websocket_upgrade: true,
|
||||||
|
http2_support: true,
|
||||||
|
certificate_id: certId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
import Docker from "dockerode";
|
||||||
|
import { writeFileSync } from "fs";
|
||||||
|
import * as process from "process";
|
||||||
|
import rimraf from "rimraf";
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
import getPort, { portNumbers } from 'get-port';
|
||||||
|
import { INTERNAL_IP } from "../config.js";
|
||||||
|
const docker = new Docker();
|
||||||
|
export async function createContainer(imageName, containerName) {
|
||||||
|
const port = await getPort({ host: INTERNAL_IP, port: portNumbers(52300, 52399) });
|
||||||
|
if (await isContainerNameInUse(containerName)) {
|
||||||
|
await stopAndRemoveContainerByName(containerName);
|
||||||
|
}
|
||||||
|
const containerOptions = {
|
||||||
|
Image: imageName,
|
||||||
|
name: containerName,
|
||||||
|
WorkingDir: '/app',
|
||||||
|
HostConfig: {
|
||||||
|
AutoRemove: false,
|
||||||
|
RestartPolicy: {
|
||||||
|
Name: "always"
|
||||||
|
},
|
||||||
|
PortBindings: {
|
||||||
|
'3000/tcp': [{ HostPort: '' + port }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const container = await docker.createContainer(containerOptions);
|
||||||
|
await container.start();
|
||||||
|
console.log("Started", containerName, "with port", port, '> 3000');
|
||||||
|
await checkContainerStatus(container.id);
|
||||||
|
return {
|
||||||
|
id: container.id,
|
||||||
|
port
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error("Error creating container:", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function listContainers() {
|
||||||
|
return (await docker.listContainers())
|
||||||
|
.map(v => v.Names[0])
|
||||||
|
.filter((full) => {
|
||||||
|
return full.startsWith('deploy-');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export async function getContainerInfo(containerId) {
|
||||||
|
const docker = new Docker();
|
||||||
|
const container = docker.getContainer(containerId);
|
||||||
|
const containerInfo = await container.inspect();
|
||||||
|
return containerInfo;
|
||||||
|
}
|
||||||
|
export async function checkImageExists(imageName) {
|
||||||
|
const images = await docker.listImages();
|
||||||
|
const imageExists = images.some(image => {
|
||||||
|
if (image.RepoTags) {
|
||||||
|
return image.RepoTags.includes(imageName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return imageExists;
|
||||||
|
}
|
||||||
|
export async function pullImage(imageName) {
|
||||||
|
const imageExists = await checkImageExists(imageName);
|
||||||
|
if (!imageExists) {
|
||||||
|
console.log(`Pulling image ${imageName}`);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
docker.pull(imageName, (err, stream) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
docker.modem.followProgress(stream, (err, output) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
console.log(`Image ${imageName} has been pulled`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(`Image ${imageName} already exists`);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function attachLogs(containerId) {
|
||||||
|
const container = docker.getContainer(containerId);
|
||||||
|
const logsStream = await container.logs({
|
||||||
|
follow: true,
|
||||||
|
stdout: true,
|
||||||
|
stderr: true,
|
||||||
|
});
|
||||||
|
return logsStream;
|
||||||
|
}
|
||||||
|
export async function isContainerNameInUse(name) {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
return containers.some((container) => container.Names.includes(`/${name}`));
|
||||||
|
}
|
||||||
|
async function stopAndRemoveContainerByName(name) {
|
||||||
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
const matchingContainers = containers.filter(container => container.Names.includes(`/${name}`));
|
||||||
|
if (matchingContainers.length === 0) {
|
||||||
|
throw new Error(`No container with name '${name}' was found`);
|
||||||
|
}
|
||||||
|
const stoppedContainer = docker.getContainer(matchingContainers[0].Id);
|
||||||
|
try {
|
||||||
|
await stoppedContainer.stop();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(`Failed to stop container ${name}: ${error.message}`);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await stoppedContainer.remove();
|
||||||
|
console.log(`Container ${name} removed`);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(`Failed to remove container ${name}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function checkContainerStatus(containerId) {
|
||||||
|
const container = docker.getContainer(containerId);
|
||||||
|
const containerInfo = await container.inspect();
|
||||||
|
const status = containerInfo.State.Status;
|
||||||
|
console.log(`Container status: ${status}`);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
export async function runCommandInContainer(containerId, command) {
|
||||||
|
console.log('$', ...command);
|
||||||
|
const container = await docker.getContainer(containerId);
|
||||||
|
const exec = await container.exec({
|
||||||
|
Cmd: command,
|
||||||
|
AttachStdout: true,
|
||||||
|
AttachStderr: true,
|
||||||
|
});
|
||||||
|
const stream = await exec.start({});
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
container.modem.demuxStream(stream, process.stdout, process.stderr);
|
||||||
|
stream.on('end', resolve);
|
||||||
|
stream.on('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export async function restartContainer(containerId) {
|
||||||
|
const docker = new Docker();
|
||||||
|
const container = await docker.getContainer(containerId);
|
||||||
|
console.log(`Restarting container ${containerId}...`);
|
||||||
|
await container.restart();
|
||||||
|
await checkContainerStatus(containerId);
|
||||||
|
}
|
||||||
|
export async function stopContainer(id) {
|
||||||
|
const docker = new Docker();
|
||||||
|
const container = await docker.getContainer(id);
|
||||||
|
await container.stop();
|
||||||
|
await checkContainerStatus(id);
|
||||||
|
}
|
||||||
|
export async function startContainer(id) {
|
||||||
|
const docker = new Docker();
|
||||||
|
const container = await docker.getContainer(id);
|
||||||
|
await container.start();
|
||||||
|
await checkContainerStatus(id);
|
||||||
|
}
|
||||||
|
function createDockerfile(cloneUrl, branch) {
|
||||||
|
return `
|
||||||
|
FROM node:lts-alpine3.17
|
||||||
|
|
||||||
|
RUN apk add git
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN git clone "${cloneUrl}" /app --depth 1 -b ${branch}
|
||||||
|
|
||||||
|
RUN yarn && yarn build
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD yarn start`.trim();
|
||||||
|
}
|
||||||
|
export async function buildDockerImage(options) {
|
||||||
|
const { name: context } = tmp.dirSync();
|
||||||
|
const { user, name, branch, cloneUrl } = options;
|
||||||
|
const imageName = `${user}/${name}:${branch}`;
|
||||||
|
let id = null;
|
||||||
|
try {
|
||||||
|
writeFileSync(context + '/Dockerfile', createDockerfile(cloneUrl, branch));
|
||||||
|
const stream = await docker.buildImage({
|
||||||
|
src: ['Dockerfile'],
|
||||||
|
context,
|
||||||
|
}, {
|
||||||
|
//@ts-ignore
|
||||||
|
nocache: true,
|
||||||
|
t: imageName
|
||||||
|
});
|
||||||
|
//@ts-ignore
|
||||||
|
stream.on('data', d => {
|
||||||
|
const data = JSON.parse(d);
|
||||||
|
const text = data.stream ?? '';
|
||||||
|
process.stdout.write(text);
|
||||||
|
if (text.startsWith("Successfully built")) {
|
||||||
|
const potentialId = text.split(" ")[2];
|
||||||
|
id = potentialId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
//@ts-ignore
|
||||||
|
docker.modem.followProgress(stream, () => {
|
||||||
|
resolve(void 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (id === null)
|
||||||
|
throw new Error("Unable to generate image " + imageName);
|
||||||
|
console.log("Built Image", imageName);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log('do we get here?');
|
||||||
|
await rimraf(context);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
await rimraf(context);
|
||||||
|
return imageName;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
import * as console from "console";
|
||||||
|
import { NPM_BASE_URL, NPM_EMAIL, NPM_PASSWORD } from "../config.js";
|
||||||
|
let bearer = null;
|
||||||
|
const headers = () => {
|
||||||
|
const headers = {
|
||||||
|
Authorization: "Bearer " + bearer,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
};
|
||||||
|
return headers;
|
||||||
|
};
|
||||||
|
async function _post(url, body) {
|
||||||
|
const res = await fetch(NPM_BASE_URL + url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers: headers()
|
||||||
|
});
|
||||||
|
if (Math.floor(res.status / 100) !== 2) {
|
||||||
|
throw new Error(JSON.stringify(await res.json(), null, 2));
|
||||||
|
}
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
async function _get(url) {
|
||||||
|
const res = await fetch(NPM_BASE_URL + url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: headers()
|
||||||
|
});
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
async function _delete(url) {
|
||||||
|
const res = await fetch(NPM_BASE_URL + url, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: headers()
|
||||||
|
});
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
function setToHappen(fn, date) {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var diff = date.getTime() - now;
|
||||||
|
return setTimeout(fn, diff);
|
||||||
|
}
|
||||||
|
async function auth() {
|
||||||
|
console.log("Attempting authentication against nginx");
|
||||||
|
const { token, expires } = await _post('/tokens', {
|
||||||
|
identity: NPM_EMAIL,
|
||||||
|
secret: NPM_PASSWORD
|
||||||
|
});
|
||||||
|
setToHappen(auth, new Date(new Date(expires).getTime() - 60 * 1000));
|
||||||
|
bearer = token;
|
||||||
|
}
|
||||||
|
export function getProxyHosts() {
|
||||||
|
return _get('/nginx/proxy-hosts');
|
||||||
|
}
|
||||||
|
export const ready = auth();
|
||||||
|
export async function isDomainRegistered(domain) {
|
||||||
|
const hosts = await getProxyHosts();
|
||||||
|
return hosts.map(h => h.domain_names).flat().some(d => d === domain);
|
||||||
|
}
|
||||||
|
export async function getProxyHostIdByDomain(domain) {
|
||||||
|
const hosts = await getProxyHosts();
|
||||||
|
for (const host of hosts) {
|
||||||
|
for (const d of host.domain_names) {
|
||||||
|
if (domain === d) {
|
||||||
|
return host.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export async function createProxyHost(domains, port, host, additionalConfig) {
|
||||||
|
const registered = (await Promise.all(domains.map(d => isDomainRegistered(d)))).some(v => v);
|
||||||
|
if (registered) {
|
||||||
|
throw new Error("Domain is already registered as a proxy host");
|
||||||
|
}
|
||||||
|
const res = await _post('/nginx/proxy-hosts', {
|
||||||
|
domain_names: domains,
|
||||||
|
forward_scheme: "http",
|
||||||
|
forward_host: host,
|
||||||
|
forward_port: port,
|
||||||
|
block_exploits: false,
|
||||||
|
allow_websocket_upgrade: false,
|
||||||
|
access_list_id: "0",
|
||||||
|
certificate_id: 0,
|
||||||
|
ssl_forced: false,
|
||||||
|
http2_support: false,
|
||||||
|
meta: {
|
||||||
|
letsencrypt_agree: false,
|
||||||
|
dns_challenge: false
|
||||||
|
},
|
||||||
|
advanced_config: "",
|
||||||
|
locations: [],
|
||||||
|
caching_enabled: false,
|
||||||
|
hsts_enabled: false,
|
||||||
|
hsts_subdomains: false,
|
||||||
|
...additionalConfig
|
||||||
|
});
|
||||||
|
console.log('Created proxy host for', domains.join(', '));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
export async function createCertificate(domains) {
|
||||||
|
const certReq = {
|
||||||
|
domain_names: domains,
|
||||||
|
meta: {
|
||||||
|
dns_challenge: false,
|
||||||
|
letsencrypt_agree: true,
|
||||||
|
letsencrypt_email: NPM_EMAIL
|
||||||
|
},
|
||||||
|
provider: "letsencrypt"
|
||||||
|
};
|
||||||
|
const res = await _post('/nginx/certificates', certReq);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
export async function getCertificates() {
|
||||||
|
return await _get('/nginx/certificates');
|
||||||
|
}
|
||||||
|
function compareSets(a, b) {
|
||||||
|
if (a.length !== b.length)
|
||||||
|
return false;
|
||||||
|
const _a = a.sort();
|
||||||
|
const _b = b.sort();
|
||||||
|
for (let i = 0; i < _a.length; i++) {
|
||||||
|
if (_a[i] !== _b[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
export async function deleteCertificate(id) {
|
||||||
|
const success = await _delete(`/nginx/certificate/${id}`);
|
||||||
|
if (success !== 'true') {
|
||||||
|
throw Error('Failed to delete certificate ' + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function getCertificateByDomains(domains) {
|
||||||
|
const certs = await getCertificates();
|
||||||
|
for (const cert of certs) {
|
||||||
|
if (compareSets(cert.domain_names, domains)) {
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
export async function hasCerficateByDomains(domains) {
|
||||||
|
return (await getCertificateByDomains(domains)) !== null;
|
||||||
|
}
|
||||||
|
export async function deleteProxyHostByDomain(domain) {
|
||||||
|
const id = await getProxyHostIdByDomain(domain);
|
||||||
|
await _delete(`/nginx/proxy-hosts/${id}`);
|
||||||
|
console.log('deleted proxy host for', domain);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
const getFlag = (name) => {
|
||||||
|
return (!!process.env[name] && /^true$/i.test(process.env[name]));
|
||||||
|
};
|
||||||
|
const getNumber = (name, fallback) => {
|
||||||
|
const n = parseInt(process.env[name]);
|
||||||
|
if (Number.isNaN(n) || typeof n !== 'number')
|
||||||
|
return fallback;
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
export const URL_AUTH = getFlag('URL_AUTH');
|
||||||
|
export const BASE_DOMAIN = process.env.BASE_DOMAIN;
|
||||||
|
export const DEPLOY_TOKEN = process.env.DEPLOY_TOKEN;
|
||||||
|
export const NPM_EMAIL = process.env.NPM_EMAIL;
|
||||||
|
export const NPM_PASSWORD = process.env.NPM_PASSWORD;
|
||||||
|
export const NPM_BASE_URL = process.env.NPM_BASE_URL;
|
||||||
|
export const INTERNAL_IP = process.env.INTERNAL_IP;
|
||||||
|
// generally you should use host unless DNS is skipped, then IP as fallback.
|
||||||
|
// but an ip is an address, so fallback to it here.
|
||||||
|
export const INTERNAL_ADDRESS = process.env.INTERNAL_ADDRESS ?? INTERNAL_IP;
|
||||||
|
export const PORT = getNumber('PORT', 6969);
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { listen } from './routes.js';
|
||||||
|
import { PORT } from './config.js';
|
||||||
|
import * as npm from './apis/npm.js';
|
||||||
|
// const id = await createContainer('hello-world');
|
||||||
|
// const stream = await attachLogs(id)
|
||||||
|
// stream.pipe(process.stdout);
|
||||||
|
// await new Promise(res => {
|
||||||
|
// stream.on('close', () => {
|
||||||
|
// res(void 0);
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
await npm.ready;
|
||||||
|
listen(PORT);
|
||||||
|
// console.log(await getProxyHosts());
|
||||||
|
// console.log((await listContainers()).map(container => container.Names));
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import express from 'express';
|
||||||
|
import deploy from './actions/deploy.js';
|
||||||
|
import { DEPLOY_TOKEN } from './config.js';
|
||||||
|
export function listen(port) {
|
||||||
|
const app = express();
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
let givenToken = req.query.token;
|
||||||
|
if (givenToken !== DEPLOY_TOKEN) {
|
||||||
|
res.statusCode = 403;
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
app.post('/deploy', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { cloneUrl, branch = 'HEAD' } = req.query;
|
||||||
|
res.json({ status: "Acknowledged", cloneUrl, branch });
|
||||||
|
await deploy({
|
||||||
|
cloneUrl: cloneUrl,
|
||||||
|
branch: branch
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
// res.json(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log('Listening on port', port);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon -e ts,env,json -x yarn -- ts-node --esm ./src/main.ts",
|
"dev": "nodemon -e ts,env,json -x yarn -- ts-node --esm ./src/main.ts",
|
||||||
"deploy": "docker-compose down && yarn build && docker-compose up -d",
|
"deploy": "docker-compose down && docker-compose build && docker-compose up -d",
|
||||||
"build": "yarn tsc && docker-compose build --no-cache"
|
"build": "DOCKER_BUILDKIT=0 docker-compose build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/dockerode": "^3.3.14",
|
"@types/dockerode": "^3.3.14",
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,9 @@ export async function createContainer(imageName: string, containerName: string):
|
||||||
|
|
||||||
export async function listContainers() {
|
export async function listContainers() {
|
||||||
return (await docker.listContainers())
|
return (await docker.listContainers())
|
||||||
.filter((container) => {
|
.map(v => v.Names[0])
|
||||||
return container.Names[0].startsWith('/deploy-');
|
.filter((full: string) => {
|
||||||
|
return full.startsWith('deploy-');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import deploy from './actions/deploy.js';
|
import deploy from './actions/deploy.js';
|
||||||
import { listContainers } from './apis/docker.js';
|
|
||||||
import { DEPLOY_TOKEN } from './config.js';
|
import { DEPLOY_TOKEN } from './config.js';
|
||||||
|
|
||||||
export function listen(port: number) {
|
export function listen(port: number) {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
console.log('incomming request', req.query, req.url, req.body);
|
console.log('incomming request', req.query, req.url, req.body);
|
||||||
let givenToken = req.query.token
|
let givenToken = req.query.token
|
||||||
|
|
@ -31,10 +29,6 @@ export function listen(port: number) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/containers', async (req, res) => {
|
|
||||||
res.json(await listContainers());
|
|
||||||
})
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log('Listening on port', port);
|
console.log('Listening on port', port);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue