Skip to content

Commit

Permalink
feat: automate http deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan D Shaw committed Jul 7, 2022
1 parent c17e3ca commit 2a6947d
Show file tree
Hide file tree
Showing 16 changed files with 407 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/ec2/
/sites/
node_modules
/sites.json/
/sites.json
63 changes: 63 additions & 0 deletions config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { existsSync, readFileSync, writeFileSync } from 'fs';

export const validateHost = (host) => {
if (/^(http|https):\/\//.test(host)) {
console.log('Scheme (http:// or https://) for host must be omitted.');
process.exit(1);
}
};

export const validateConfig = (config) => {
if (
!config ||
config === true ||
Array.isArray(config) ||
config.length !== undefined ||
typeof config === "number"
) {
console.log("Configuration file is not valid.");
process.exit(1);
}

if (!config.ec2) {
console.log("'ec2' is required.");
process.exit(1);
}

if (!config.ec2.host) {
console.log("'ec2.host' is required.");
process.exit(1);
}

validateHost(config.ec2.host);
};

export const getConfigPath = () => {
const args = process.argv.slice(2);
const rawconfigf = args[0] ? args[0] : null;
return rawconfigf;
}

export const getConfig = () => {
const args = process.argv.slice(2);
const rawconfigf = args[0] ? args[0] : null;

if (rawconfigf === null) {
console.log('A path to a valid JSON file is required as the first argument.');
process.exit(1);
}

if (!existsSync(rawconfigf)) {
console.log(`${rawconfigf} doesnt exist`);
process.exit(1);
}

const rawconfig = JSON.parse(readFileSync(rawconfigf, 'utf8'));
validateConfig(rawconfig);

return rawconfig;
}

export const updateConfigFile = (config) => {
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
}
42 changes: 42 additions & 0 deletions ec2-init.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { exec } from 'child_process';
import _ from 'lodash';
import { updateConfigFile } from './config.mjs';
import { SSH, shell, genPwd } from "./utils.mjs";

/**
* Initialize kusanagi (Nginx, MySQL, etc)
*/
export const ec2Init = (config, callback) => {
const client = new SSH(config);

client.sshCentos("sudo dnf update -y");

exec(`ssh -i ${config.ec2.centos.pem} -t centos@${config.ec2.host} "sudo reboot"`, () => {
console.log('Rebooted. Waiting for instance to come back online...')
shell('sleep 60');

const kusanagiPwd = genPwd();
const dbpwd = genPwd();

const outjson = _.cloneDeep(config);

client.sshCentos(
`sudo su - -c 'kusanagi init --tz Asia/Tokyo --lang ja --keyboard en --passwd \"${kusanagiPwd}\" --nophrase --dbrootpass \"${dbpwd}\" --nginx121 --php74 --mariadb10.5'`
);

outjson.ec2.kusanagi.userpwd = kusanagiPwd;
outjson.ec2.mysqlRootPass = dbpwd;
updateConfigFile(outjson);

client.sshCentos(
'sudo mv /root/kusanagi.pem /home/centos/ && sudo chown centos:centos /home/centos/kusanagi.pem'
);

// download kusanagi SSH private key
client.downloadCentos("/home/centos/kusanagi.pem", "./");
shell(`mv -f ./kusanagi.pem ${config.ec2.kusanagi.pem}`);
shell(`chmod 400 ${config.ec2.kusanagi.pem}`);

callback();
});
};
6 changes: 6 additions & 0 deletions ec2-init.run.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node
import { getConfig } from './config.mjs';
import { ec2Init } from './ec2-init.mjs';

const config = getConfig();
ec2Init(config);
17 changes: 10 additions & 7 deletions examples/sites.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
{
"host": "ec2-11-111-11-11.ap-northeast-3.compute.amazonaws.com",
"kusanagi": {
"password": "somepassword"
"domain": "mydomain-name.com",
"ec2": {
"host": "ec2-11-111-11-11.ap-northeast-3.compute.amazonaws.com",
"centos": {
"pem": "./ec2/aivec.co.jp-centos.pem"
},
"kusanagi": {
"pem": "./ec2/aivec.co.jp-kusanagi.pem"
}
},
"rootsite": {
"host": "my.site.com",
"dbname": "mydbname",
"dbuser": "mydbuser",
"dbpass": "mydbpass",
"wpuser": "mywpuser"
},
"subsites": [
{
"host": "my.site.com/subsite",
"name": "subsite-folder-name",
"dbname": "mysubdbname",
"dbuser": "mysubdbuser",
"dbpass": "mysubdbpass",
"wpuser": "mysubwpuser"
}
]
Expand Down
21 changes: 21 additions & 0 deletions nginx-configure.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SSH } from "./utils.mjs";

/**
* Configures Nginx to properly route subdirs to their corresponding WordPress install
*/
export const nginxConfigure = (config) => {
const client = new SSH(config);

const commands = [];
commands.push("cd /etc/opt/kusanagi/nginx/conf.d;");
config.subsites.forEach((subsite) => {
commands.push(
`echo \\"upstream ${subsite.name} { server 127.0.0.1; }\\" > ${subsite.name}.upstream.conf;`
);

client.sshCentos(`sudo sed -i '/root\\\s\\/home\\/kusanagi\\/${config.rootsite.name}\\/DocumentRoot/a "location ^~ /${subsite.name}/ { \\nproxy_pass http://${subsite.name}/ \\n}"' /etc/opt/kusanagi/nginx/conf.d/${config.rootsite.name}.conf`);
});
commands.push("kusanagi nginx --reload;");

client.sshCentos(`sudo su - -c '${commands.join(" ")}'`);
};
6 changes: 6 additions & 0 deletions nginx-configure.run.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node
import { getConfig } from './config.mjs';
import { nginxConfigure } from './nginx-configure.mjs';

const config = getConfig();
nginxConfigure(config);
39 changes: 39 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"generate-password": "^1.7.0",
"lodash": "^4.17.21"
}
}
34 changes: 34 additions & 0 deletions provision.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import _ from "lodash";
import { generate } from "generate-password";
import { updateConfigFile } from "./config.mjs";
import { SSH, genPwd } from "./utils.mjs";

export const provision = (config) => {
const utils = new SSH(config);

const dbpass = genPwd();

const outjson = _.cloneDeep(config);

utils.sshKusanagi(
`kusanagi provision --wp --wplang ja --fqdn ${config.ec2.host} --no-email --dbname ${config.rootsite.dbname} --dbuser ${config.rootsite.dbuser} --dbpass '${dbpass}' '${config.rootsite.name}'`
);

outjson.rootsite.dbpass = dbpass;
outjson.rootsite.fullname = config.rootsite.name;
outjson.rootsite.url = config.ec2.host;
updateConfigFile(outjson);

config.subsites.forEach((subsite, i) => {
const fullname = `${config.rootsite.name}-${subsite.name}`;
const subdbpass = genPwd();
utils.sshKusanagi(
`kusanagi provision --wp --wplang ja --fqdn ${subsite.name} --no-email --dbname ${subsite.dbname} --dbuser ${subsite.dbuser} --dbpass '${subdbpass}' '${fullname}'`
);

outjson.subsites[i].dbpass = subdbpass;
outjson.subsites[i].fullname = fullname;
outjson.subsites[i].url = `${config.ec2.host}/${subsite.name}`;
updateConfigFile(outjson);
});
};
6 changes: 6 additions & 0 deletions provision.run.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node
import { getConfig } from './config.mjs';
import { provision } from './provision.mjs';

const config = getConfig();
provision(config);
30 changes: 10 additions & 20 deletions run.mjs
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
#!/usr/bin/env node
import { existsSync, readFileSync } from 'fs';
import { validateConfig } from './validate.mjs';

const args = process.argv.slice(2);
const rawconfigf = args[0] ? args[0] : null;

if (rawconfigf === null) {
console.log('A path to a valid JSON file is required as the first argument.');
process.exit(1);
}

if (!existsSync(rawconfigf)) {
console.log(`${rawconfigf} doesnt exist`);
process.exit(1);
}

const rawconfig = JSON.parse(readFileSync(rawconfigf, 'utf8'));
console.log(rawconfig);

validateConfig({ host: 'mysite.com'});
import { getConfig } from './config.mjs';
import { ec2Init } from './ec2-init.mjs';
import { provision } from './provision.mjs';
import { wpInstall } from './wp-install.mjs';

const config = getConfig();
ec2Init(config, () => {
provision(config);
wpInstall(config);
});
52 changes: 52 additions & 0 deletions utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { generate } from "generate-password";
import { execSync } from "child_process";

export const shell = (command) => execSync(command, {
shell: '/bin/bash',
stdio: 'inherit',
});

export const genPwd = () => {
return generate({
length: 20,
symbols: "%_#",
numbers: true,
strict: true,
});
}

export class SSH {
finalc = "";

constructor(finalc) {
this.finalc = finalc;
}

sshCentos(command) {
shell(`chmod 400 ${this.finalc.ec2.centos.pem}`);
shell(
`ssh -i ${this.finalc.ec2.centos.pem} -t centos@${this.finalc.ec2.host} "${command}"`
);
}

sshKusanagi(command) {
shell(`chmod 400 ${this.finalc.ec2.kusanagi.pem}`);
shell(
`ssh -i ${this.finalc.ec2.kusanagi.pem} -t kusanagi@${this.finalc.ec2.host} "${command}"`
);
}

uploadKusanagi(localpath, remotepath) {
shell(`chmod 400 ${this.finalc.ec2.kusanagi.pem}`);
shell(
`scp -i ${this.finalc.ec2.kusanagi.pem} ${localpath} kusanagi@${this.finalc.ec2.host}:${remotepath}`
);
}

downloadCentos(remotepath, localpath) {
shell(`chmod 400 ${this.finalc.ec2.centos.pem}`);
shell(
`scp -i ${this.finalc.ec2.centos.pem} centos@${this.finalc.ec2.host}:${remotepath} ${localpath}`
);
}
}
26 changes: 0 additions & 26 deletions validate.mjs

This file was deleted.

Loading

0 comments on commit 2a6947d

Please sign in to comment.