limgen
Version:
Infrastructure as Code generator
183 lines (182 loc) • 7.06 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderIndex = exports.envPull = exports.collectInput = exports.inputs = exports.dependsOn = void 0;
const ejs_1 = __importDefault(require("ejs"));
const path_1 = __importDefault(require("path"));
const prompts_1 = __importDefault(require("prompts"));
const promises_1 = __importDefault(require("fs/promises"));
const schema_1 = require("../../schema");
const files_1 = require("../../files");
const project_1 = require("../../project");
const exec_1 = require("../../utils/exec");
const dependsOn = (opts) => __awaiter(void 0, void 0, void 0, function* () {
const files = [
'components/app-fargate.ts',
'components/cdn-cloudfront.ts',
'components/lb-alb-public.ts',
'components/vpc-public.ts',
'utils/deep-merge.ts',
'utils/prefixed.ts',
];
const packages = [
'@pulumi/aws',
'@pulumi/awsx',
'@pulumi/pulumi',
'zod',
];
if (opts.includeStorage) {
files.push('components/storage-s3.ts');
}
if (opts.includeDb) {
files.push('components/db-postgres-rds.ts');
packages.push('@pulumi/random');
}
if (opts.networkType === 'private') {
files.push('components/bastion-ec2.ts');
}
return {
files,
packages,
};
});
exports.dependsOn = dependsOn;
const inputs = () => __awaiter(void 0, void 0, void 0, function* () {
return [
{
name: 'includeStorage',
message: 'Include storage',
schema: (0, schema_1.cliBoolean)(),
},
{
name: 'includeDb',
message: 'Include a database',
schema: (0, schema_1.cliBoolean)(),
},
{
name: 'networkType',
message: 'Network type',
schema: (0, schema_1.cliEnum)(['public', 'private']).optional(),
},
{
name: 'port',
message: 'Port to expose',
schema: (0, schema_1.cliInteger)().optional().default('3000'),
}
];
});
exports.inputs = inputs;
const collectInput = (cmdArgs, projectArgs) => __awaiter(void 0, void 0, void 0, function* () {
let includeStorage;
if (projectArgs.includeStorage === 'unknown') {
const answer = yield (0, prompts_1.default)({
type: 'confirm',
name: 'includeStorage',
message: 'Include storage?',
initial: true,
});
includeStorage = answer.includeStorage;
}
else {
includeStorage = projectArgs.includeStorage === 'true';
}
let includeDb;
if (projectArgs.includeDb === 'unknown') {
const answer = yield (0, prompts_1.default)({
type: 'confirm',
name: 'includeDb',
message: 'Include a database?',
initial: true,
});
includeDb = answer.includeDb;
}
else {
includeDb = projectArgs.includeDb === 'true';
}
let networkType = projectArgs.networkType;
if (projectArgs.networkType === 'unknown') {
const answer = yield (0, prompts_1.default)({
type: 'select',
name: 'networkType',
message: 'Network type',
choices: [
{ title: 'Public (simpler, suitable for development)', value: 'public' },
{ title: 'Private (more secure, requires tunnel to access database)', value: 'private' },
],
initial: 0,
});
networkType = answer.networkType;
}
return {
includeStorage,
includeDb,
networkType,
port: projectArgs.port,
};
});
exports.collectInput = collectInput;
const envPull = ({ projectName, stack, }) => __awaiter(void 0, void 0, void 0, function* () {
const metadata = yield (0, project_1.readProjectMetadata)({ projectName });
const projectInputs = metadata.projectInputs;
const properties = {};
if (projectInputs.includeStorage) {
const { stdout: BUCKET_NAME } = yield (0, exec_1.execPromise)(`pulumi stack output objectStorageBucket --stack ${stack}`, { cwd: path_1.default.join('infrastructure', 'projects', projectName) });
Object.assign(properties, { BUCKET_NAME });
}
if (projectInputs.includeDb) {
const { stdout: secretId } = yield (0, exec_1.execPromise)(`pulumi stack output dbSecret --stack ${stack}`, { cwd: path_1.default.join('infrastructure', 'projects', projectName) });
const { stdout: secretResponse } = yield (0, exec_1.execPromise)(`aws secretsmanager get-secret-value --secret-id ${secretId}`);
const DATABASE_URL = JSON.parse(secretResponse).SecretString;
if (!DATABASE_URL) {
throw new Error(`Could not get secret value for ${secretId}`);
}
Object.assign(properties, { DATABASE_URL });
}
yield promises_1.default.writeFile('.env', Object.entries(properties).map(([key, value]) => `${key}=${value}`.trim()).join('\n'));
});
exports.envPull = envPull;
function fullstackAWSProject(inputs) {
return __awaiter(this, void 0, void 0, function* () {
const [indexContents] = yield Promise.all([
(0, exports.renderIndex)(inputs),
updateDockerignore(),
]);
return indexContents;
});
}
exports.default = fullstackAWSProject;
const updateDockerignore = () => __awaiter(void 0, void 0, void 0, function* () {
if (yield (0, files_1.fileExists)('.dockerignore')) {
// see if infrastructure is already in the .dockerignore file
const dockerignore = yield promises_1.default.readFile('.dockerignore', 'utf-8');
if (!dockerignore.includes('infrastructure')) {
yield promises_1.default.appendFile('.dockerignore', '\ninfrastructure\n');
}
}
else {
yield promises_1.default.writeFile('.dockerignore', `
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
infrastructure/`.trim());
}
});
const renderIndex = (inputs) => __awaiter(void 0, void 0, void 0, function* () {
return ejs_1.default.renderFile(path_1.default.join(__dirname, 'template.ejs.t'), inputs);
});
exports.renderIndex = renderIndex;