@adp-psych/container-tools
Version:
Tools for using containers for psychology experiments
134 lines (123 loc) • 4 kB
JavaScript
/*
* Copyright (C) 2021 Anthony Di Pietro
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* @file Installs an experiment
* to a [Kubernetes](https://kubernetes.io/) cluster
* using [Helm](https://helm.sh/).
*
* @module module:install-experiment
* @requires console-exec
* @requires generate-selfsigned-certificate
* @author Anthony Di Pietro <anthony.dipietro@research.uwa.edu.au>
* @copyright © 2021 Anthony Di Pietro
* @license AGPL-3.0-or-later
*/
const fs = require('node:fs/promises');
const {tmpdir} = require('node:os');
const path = require('node:path');
const pkgBasename = require('@adp-psych/pkg-basename');
const {consoleSpawn} = require('./console-exec.js');
const generateSelfsignedCertificate =
require('./generate-selfsigned-certificate.js');
const {upgradeInstall} = require('./helm.js');
/**
* The filename of the private key for the TLS certificate.
*
* @constant {String}
* @static
* @access protected
*/
const KEY_FILENAME = 'privkey.pem';
/**
* The filename of the TLS certificate.
*
* @constant {String}
* @static
* @access protected
*/
const CERTIFICATE_FILENAME = 'cert.pem';
/**
* Creates a
* [Kubernetes TLS secret](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets).
*
* @static
* @access protected
* @param {String} keyFilename - The filename of the private key.
* @param {String} certificateFilename - The filename of the certificate.
* @example
* createTlsSecret('tls/privkey.pem', 'tls/cert.pem');
*/
const createTlsSecret = async (keyFilename, certificateFilename) => {
const pkg = pkgBasename();
try {
await consoleSpawn('kubectl', [
'delete',
'secret',
`${pkg}-tls`,
]);
} catch {
/* Ignore failure to delete secret, as it may not exist. */
}
await consoleSpawn('kubectl', [
'create',
'secret',
'tls',
`${pkg}-tls`,
`--cert=${certificateFilename}`,
`--key=${keyFilename}`,
]);
};
/**
* Installs/upgrades the experiment using Helm.
*
* @static
* @access protected
* @param {String} chartDirectory - The path of the chart directory.
* This should contain a directory named with the experiment's package
* name that contains the chart files for the experiment.
* @example
* helmUpgradeExperiment('build/helm'); // Installs/upgrades the experiment.
*/
const helmUpgradeExperiment = async (chartDirectory) => {
const pkg = pkgBasename();
await upgradeInstall(pkg, path.join(chartDirectory, pkg), []);
};
/**
* Installs/upgrades the experiment using Helm.
*
* @static
* @param {String} chartDirectory - The path of the chart directory.
* This should contain a directory named with the experiment's package
* name that contains the chart files for the experiment.
* @example
* installExperiment('build/helm'); // Installs/upgrades the experiment.
*/
const installExperiment = async (chartDirectory) => {
const pkg = pkgBasename();
const tlsDirectory = await fs.mkdtemp(
path.join(tmpdir(), `${pkg}-tls-`),
);
const keyFilename = path.join(tlsDirectory, KEY_FILENAME);
const certificateFilename = path.join(
tlsDirectory, CERTIFICATE_FILENAME,
);
await generateSelfsignedCertificate(keyFilename, certificateFilename);
await createTlsSecret(keyFilename, certificateFilename);
await helmUpgradeExperiment(chartDirectory);
await fs.rm(tlsDirectory, {'recursive': true});
};
module.exports = installExperiment;