Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
building out OSX script generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoe committed Jun 15, 2014
1 parent 400bdca commit c7eb734
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
.DS_Store
logs/ndm-test.log

28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ An ndm deployment directory consists of:
* an **service.json** file, used to specify meta-information about the service being deployed.
* **environment variables**
* **process counts**, how many copies of the service should be run?
* a **environments/** folder, in the environments folder you can override `service.json` on an environment, by environment basis:
* `ndm deploy staging`, will look for **staging.json** in the environments folder, and override **service.json** with it.

service.json
-----------
Expand All @@ -74,21 +72,25 @@ A typical **service.json** file looks something like this:

```json
{
"services": {
"npm-www": {
"procs": 3,
"environment": {
"PORT": "500%PROC_NUMBER",
}
"npm-www-1": {
"module": "npm-www",
"env": {
"PORT": "5000",
}
},
"environment": {
"npm-www-2": {
"module": "npm-www",
"env": {
"PORT": "5001",
}
},
"env": {
"COUCH": "http://registry.example.com"
}
}
```

* **services:** service specific configuration:
* **procs:** how many copies of the service should we run per-host? defaults to `1`.
* **environment:** process-specific environment variables.
* **environment:** environment variables shared across services.
* **service-name:** name to associate with the daemon script:
* **module:** npm-module the daemon executes.
* **env:** process-specific environment variables.
* **env:** environment variables shared across services.
20 changes: 16 additions & 4 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,36 @@ function Config(opts) {
_.extend(this, {
platform: process.platform,
env: process.env,
baseWorkingDirectory: path.resolve('./node_modules')
baseWorkingDirectory: path.resolve('.')
}, opts);

// allow platform and env to be overridden before applying.
_.extend(this, this._getEnv(), this._getOSDefaults());
_.extend(this, this._getEnv(), this._getOSDefaults(), opts);
};

// os specific config variables.
Config.prototype._getOSDefaults = function(platform) {
var defaults = {
darwin: {
servicesDirectory: '~/Library/LaunchAgents/'
daemonsDirectory: '~/Library/LaunchAgents/',
daemonExtension: '.plist',
nodeBin: '/usr/local/bin/node',
npmBin: '/usr/local/bin/npm',
template: path.resolve(
__dirname, '../templates/launchctl.ejs'
)
}
}

// default to Ubuntu specific settings.
return defaults[this.platform] || {
servicesDirectory: '/etc/init'
daemonsDirectory: '/etc/init',
nodeBin: '/usr/bin/node',
npmBin: '/usr/bin/npm',
daemonExtension: '.conf',
template: path.resolve(
__dirname, '../templates/upstart.ejs'
)
}
};

Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
exports.Installer = require('./installer');
exports.Service = require('./service');
exports.Config = require('./config');
64 changes: 64 additions & 0 deletions lib/service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
var _ = require('lodash'),
fs = require('fs'),
path = require('path'),
ejs = require('ejs');

function Service(opts) {
_.extend(this,
{},
require('./config')(),
opts
);

// run the script within its ndm
// node_modules directory.
this.workingDirectory = path.resolve(
this.baseWorkingDirectory,
'./node_modules',
this.module
)

this.logFile = path.resolve(
this.baseWorkingDirectory,
'./logs',
this.name + ".log"
)
};

Service.prototype.generateScript = function() {
fs.writeFileSync(
path.resolve(this.daemonsDirectory, this.name + this.daemonExtension),
ejs.render(fs.readFileSync(this.template).toString(), this),
{
mode: 0755
}
);
};

exports.allServices = function() {
var services = [],
serviceJson = JSON.parse(fs.readFileSync(
path.resolve('./service.json')
));

Object.keys(serviceJson).forEach(function(serviceName) {
var serviceConfig = serviceJson[serviceName];

// apply sane defaults as we create
// the services.
var service = new Service(_.extend(
{
module: serviceName,
name: serviceName
},
serviceConfig
));

// populate the global env on the service.
service.env = _.extend(serviceConfig.env, serviceJson.env);

services.push(service);
});

return services;
}
Empty file added logs/.gitkeep
Empty file.
9 changes: 7 additions & 2 deletions node_modules/ndm-test/test.js

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

18 changes: 18 additions & 0 deletions service.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"ndm-test": {
"description": "thumbnailing service",
"env": {
"PORT": 8000,
"USER": "bcoe"
}
},
"ndm-test2": {
"module": "ndm-test",
"env": {
"PORT": 8080
}
},
"env": {
"APP": "my-test-app"
}
}
20 changes: 12 additions & 8 deletions templates/launchctl.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>ndm.ndm-test</string>
<string><%= name %></string>
<key>ProgramArguments</key>
<array>
<string>npm start</string>
<string><%= nodeBin %></string>
<string><%= npmBin %></string>
<string>start</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PORT</key>
<string>8888</string>
<dict><% Object.keys(env).forEach(function(key) { %>
<key><%= key %></key>
<string><%= env[key] %></string><% }); %>
</dict>
<key>EnableTransactions</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/usr/local/var</string>
<string><%= workingDirectory %></string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<string><%= logFile %></string>
<key>StandardOutPath</key>
<string>/dev/null</string>
<string><%= logFile %></string>
</dict>
</plist>
4 changes: 0 additions & 4 deletions test/cli-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
/**
Handles parsing CLI arguments, walks a user through setting
up their environment.
*/
21 changes: 12 additions & 9 deletions test/config-test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
/**
smart configuration system, that takes into accoutn CLI,
Environment, and tries to guess some sane defaults
based on OS.
*/
var Lab = require('lab'),
path = require('path'),
Config = require('../lib').Config,
_ = require('lodash');

// See prepare-tests.js, for follower feed ordering.
Lab.experiment('config', function() {
Lab.it('should be initialized with sane defaults', function(done) {
var config = Config();
Lab.expect(config.baseWorkingDirectory).to.match(/node_modules/);
Lab.expect(config.baseWorkingDirectory).to.match(/ndm/);
done();
});

Expand All @@ -26,7 +20,7 @@ Lab.experiment('config', function() {

Lab.it('should allow defaults to be overridden by environment variables', function(done) {
var config = Config({
env: _.extend(process.env, {NDM_BASE_WORKING_DIRECTORY: '/foo'})
env: {NDM_BASE_WORKING_DIRECTORY: '/foo'}
});
Lab.expect(config.baseWorkingDirectory).to.eql('/foo');
done();
Expand All @@ -36,7 +30,16 @@ Lab.experiment('config', function() {
var config = Config({
platform: 'darwin'
});
Lab.expect(config.servicesDirectory).to.eql('~/Library/LaunchAgents/');
Lab.expect(config.daemonsDirectory).to.eql('~/Library/LaunchAgents/');
done();
});

Lab.it('should allow OS specific variables to be overridden', function(done) {
var config = Config({
platform: 'darwin',
daemonsDirectory: '/foo'
});
Lab.expect(config.daemonsDirectory).to.eql('/foo');
done();
});

Expand Down
5 changes: 0 additions & 5 deletions test/installer-test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
/**
Handles installing npm dependencies, and populating
default values in ndm.json.
*/
var Lab = require('lab');

// See prepare-tests.js, for follower feed ordering.
Lab.experiment('installer', function() {

});
3 changes: 0 additions & 3 deletions test/script-generator-test.js

This file was deleted.

45 changes: 45 additions & 0 deletions test/service-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var Lab = require('lab'),
path = require('path'),
Service = require('../lib').Service,
Config = require('../lib').Config,
fs = require('fs');

Lab.experiment('service', function() {

Lab.experiment('allServices', function(done) {
Lab.it('should default module to service name, if no module stanza provided', function(done) {
var service = Service.allServices()[0];
Lab.expect(service.module).to.eql(service.name);
done();
});

Lab.it('should allow npm-module to be overridden', function(done) {
var service = Service.allServices()[1];
Lab.expect(service.module).to.eql('ndm-test');
done();
});

Lab.it('should load global environment stanza if present', function(done) {
var service = Service.allServices()[1];
Lab.expect(service.env.APP).to.eql('my-test-app');
done();
});
});

Lab.experiment('generateScript', function() {
Lab.experiment('darwin', function() {
Lab.it('should genterate a script with the appropriate variables populated', function(done) {
// test generating a script for darwin.
Config({
platform: 'darwin',
daemonsDirectory: './'
});

var service = Service.allServices()[0];
service.generateScript();
done();
});
});
});

});

0 comments on commit c7eb734

Please sign in to comment.