Permalink
Browse files

Initial commit

  • Loading branch information...
tqc committed Aug 27, 2015
0 parents commit 0b7e383571bf19f2f6ee9da4c3a62e637513e047
Showing with 302 additions and 0 deletions.
  1. +4 −0 .eslintignore
  2. +34 −0 .eslintrc
  3. +5 −0 .gitignore
  4. +75 −0 README.md
  5. +20 −0 license.txt
  6. +27 −0 package.json
  7. +30 −0 src/index.js
  8. +31 −0 src/nginx-app.conf
  9. +31 −0 src/nginx.js
  10. +45 −0 src/node.js
  11. 0 test/index.js
@@ -0,0 +1,4 @@
node_modules
built
templates/section.js
templates/page.js
@@ -0,0 +1,34 @@
{
"extends": "defaults/configurations/eslint",
"parser": "babel-eslint",
"plugins": [
],
"rules":{
"eqeqeq": 0,
"no-unused-vars": [2, {"vars": "all", "args":"none"}],
"indent": [2,4],
"quotes": 0,
"linebreak-style": [2,"unix"],
"strict": 0,
"no-console": 0,
// allow one line ifs
"curly": 0,
"eol-last": 0,
"new-cap": 0,
// Warn about todo comments so they don't get forgotten
no-warning-comments: 1,
// warnings that should really be errors but would require more complex code fixes
"no-extend-native": 1,
"no-labels": 1
},
"globals": {
},
"env": {
"es6": true,
"browser": true,
"node": true,
},
"ecmafeatures": {
"modules": true
}
}
@@ -0,0 +1,5 @@
.DS_Store
node_modules
_site
.sass-cache
npm-debug.log
@@ -0,0 +1,75 @@
# CodeDeploy Scripts
[ ![Codeship Status for tqc/codedeploy-scripts](https://codeship.com/projects/909dab90-2e9f-0133-1da1-6a18900ed8b9/status?branch=master)](https://codeship.com/projects/99161)
AWS CodeDeploy lifecycle scripts using ES6 to deploy a node app to EC2.
## Usage
npm install codedeploy-scripts
In the app folder, you only need two simple files to handle the deployment.
###appspec.yml
This tells CodeDeploy to copy everything to /apps/appname and run deployment.js for all lifecycle events. ApplicationStop is omitted, but you can use it if you are extremely confident in the quality of your code, or just enjoy manually fixing broken servers.
version: 0.0
os: linux
files:
+ source: /
destination: /apps/appname
hooks:
# ApplicationStop:
# - location: deployment.js
# timeout: 180
BeforeInstall:
+ location: deployment.js
timeout: 180
AfterInstall:
+ location: deployment.js
timeout: 180
ApplicationStart:
+ location: deployment.js
timeout: 180
ValidateService:
+ location: deployment.js
timeout: 180
### deployment.js
Extends the deployment class with any custom actions needed on CodeDeploy lifecycle events. Deployment.run() will call the appropriate method based on the LIFECYCLE_EVENT variable set by CodeDeploy.
The below code will run /apps/deploytest/server.js on port 5000, with nginx as a reverse proxy and serving static files on deploytest.example.com:80
#!/usr/local/bin/node
"use strict";
var deployTools = require("codedeploy-scripts");
class Deployment extends deployTools.Deployment {
constructor() {
this.node = new deployTools.Node("deploytest", 5000, "server.js");
this.nginx = new deployTools.Nginx(this.node, "deploytest.example.com");
super();
}
BeforeInstall() {
this.node.stop();
}
AfterInstall() {
this.nginx.configure();
}
ApplicationStart() {
this.node.start();
this.nginx.reload();
}
}
new Deployment().run();
## Assumptions
To keep things simple, the code makes a few assumptions.
* The target is a standard Amazon Linux instance
* io.js is installed as /usr/local/bin/node
* The app will be installed to /apps/appname
* static files are in /apps/appname/static and /apps/appname/built
@@ -0,0 +1,20 @@
Copyright (c) 2015 Tom Clarkson http://tqclarkson.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
{
"author": "Tom Clarkson",
"name": "codedeploy-scripts",
"description": "AWS CodeDeploy lifecycle scripts using ES6 to deploy a node app to EC2",
"version": "0.0.1",
"keywords": ["AWS", "CodeDeploy", "EC2"],
"repository": {
"url": "http://github.com/tqc/codedeploy-scripts"
},
"main": "./src/index.js",
"scripts": {
"test": "eslint . && mocha"
},
"dependencies": {
},
"devDependencies": {
"babel-eslint": "*",
"eslint": "^1.0.0",
"eslint-config-defaults": "^3.1.0",
"chai": "*",
"mocha": "*"
},
"license": "MIT",
"engines": {
"node": ">=3.0.0"
}
}
@@ -0,0 +1,30 @@
"use strict";
class Deployment {
constructor() {
}
ApplicationStop() {}
BeforeInstall() {}
AfterInstall() {}
ApplicationStart() {}
ValidateService() {}
run() {
var event = process.env.LIFECYCLE_EVENT;
if (!event) {
console.log("LIFECYCLE_EVENT is not set");
}
else console.log("Handling event " + process.env.LIFECYCLE_EVENT);
if (process.env.LIFECYCLE_EVENT == "ApplicationStop") this.ApplicationStop();
else if (process.env.LIFECYCLE_EVENT == "BeforeInstall") this.BeforeInstall();
else if (process.env.LIFECYCLE_EVENT == "AfterInstall") this.AfterInstall();
else if (process.env.LIFECYCLE_EVENT == "ApplicationStart") this.ApplicationStart();
else if (process.env.LIFECYCLE_EVENT == "ValidateService") this.ValidateService();
}
}
module.exports = {
Node: require("./node"),
Nginx: require("./nginx"),
Deployment: Deployment
};
@@ -0,0 +1,31 @@
upstream app___APPNAME__ {
server 127.0.0.1:__NODEPORT__;
keepalive 8;
}
server {
listen 80;
server_name __DOMAINS__;
location / {
root /apps/__APPNAME__/static/;
try_files $uri $uri/index.html @buildfolder;
}
location @buildfolder {
root /apps/__APPNAME__/build/prod/web/;
try_files $uri $uri/index.html @nodeapp;
}
location @nodeapp {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app___APPNAME__;
proxy_redirect off;
}
}
@@ -0,0 +1,31 @@
"use strict";
var child = require("child_process");
var fs = require("fs");
class Nginx {
constructor(node, domains) {
this.node = node;
this.appName = node.appName;
this.domains = domains;
this.nodePort = node.port;
}
configure(options) {
var confpath = "/etc/nginx/conf.d/" + this.appName + ".conf";
var conf = fs.readFileSync(__dirname + "/nginx-app.conf", "utf-8")
.replace(/__APPNAME__/ig, this.appName)
.replace(/__DOMAINS__/ig, this.domains)
.replace(/__NODEPORT__/ig, this.nodePort);
fs.writeFileSync(confpath, conf);
}
reload() {
child.spawn("/etc/init.d/nginx", ["reload"], {});
}
}
module.exports = Nginx;
@@ -0,0 +1,45 @@
"use strict";
var child = require("child_process");
function getPid(port) {
console.log("getting pid for port " + port);
try {
let ns = child.execSync("netstat -lnp", {
encoding: "utf-8",
timeout: 500
});
var lines = ns.split("\n");
for (let i = 0; i < lines.length; i++) {
var line = lines[i];
if (line.indexOf(":" + port) < 0) continue;
var m = line.match(/(\d+)\/node/);
if (m) return m[1];
}
} catch (ex) {
console.log("Error getting node process");
}
}
class Node {
constructor(appName, port, scriptPath) {
this.appName = appName;
this.port = port;
this.scriptPath = scriptPath;
this.pid = getPid(port);
}
start() {
// start node server
child.exec("export PORT=" + this.port + "; /usr/local/bin/node /apps/" + this.appName + "/" + this.scriptPath + " > /dev/null 2> /dev/null < /dev/null &", {});
}
stop() {
if (!this.pid) {
console.log("No instance found on port " + this.port);
} else {
console.log("Killing process " + this.pid + " listening on port " + this.port);
child.execSync("kill " + this.pid);
}
}
}
module.exports = Node;
No changes.

0 comments on commit 0b7e383

Please sign in to comment.