Skip to content
This repository has been archived by the owner on Jun 21, 2019. It is now read-only.

Commit

Permalink
various tweaks for prod
Browse files Browse the repository at this point in the history
  • Loading branch information
nmagerko committed Dec 18, 2016
1 parent 8adecb4 commit fe28671
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 203 deletions.
43 changes: 17 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,45 +47,36 @@ We have provided templates in the directory already with all available configura
These templates are named `{ENV}.config.template`. You should copy these templates into
files named `{ENV}.config` and fill them with sensible values; these values can be raw
values or existing environment variables. Note that changes to the templates are
commited to the project codebase, but changes to any `*.config` files are ignored.
committed to the project codebase, but changes to any `*.config` files are ignored.

A list of configuration keys is provided below:

| Key | Possible Values | Purpose |
| --- | --------------- | ------- |
| NODE_ENV | 'production' or 'development' | Determines how environment should be configured |
| PROFILE | Any string | Presents an externally-meaningful identifier |
| HACKILLINOIS_SECRET | Any string | Sets the master secret (required on production) |
| HACKILLINOIS_PORT | Any valid port number | Overrides default port (8080) |
| HACKILLINOIS_SUPERUSER_EMAIL | Any valid email | Overrides the default superuser email ('[email protected]') |
| HACKILLINOIS_SUPERUSER_PASSWORD | Any string | Overrides the default superuser password ('ABCD1234!') |
| NODE_ENV | 'production', 'development', 'testing' | Determines how environment should be configured |
| AWS | 0 or 1 | Whether or not to use AWS |
| HACKILLINOIS_ID | Any string | Sets the identifier used to represent this instance |
| HACKILLINOIS_SECRET | Any string | Sets the master secret |
| HACKILLINOIS_PORT | Any valid port number | Sets the port |
| HACKILLINOIS_SUPERUSER_EMAIL | Any valid email | Sets the default superuser email |
| HACKILLINOIS_SUPERUSER_PASSWORD | Any string | Sets the default superuser password |
| HACKILLINOIS_MAIL_KEY | Any string | Sets the mail service API key |
| DB_NAME | Any valid MySQL schema name | Overrides default name (hackillinois) |
| DB_USERNAME | Any string | Overrides default MySQL username ('root') |
| DB_PASSWORD | Any string | Overrides default MySQL password ('') |
| DB_HOSTNAME | Any valid URI | Overrides default MySQL host ('127.0.0.1') |
| DB_PORT | Any valid port number | Overrides default MySQL port (3306) |
| DB_NAME | Any valid MySQL schema name | Sets database name |
| DB_USERNAME | Any string | Sets MySQL username |
| DB_PASSWORD | Any string | Sets MySQL password |
| DB_HOSTNAME | Any valid URI | Sets MySQL host |
| DB_PORT | Any valid port number | Sets MySQL port |

Additionally, an [AWS shared credentials file](http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html)
can be made available with configuration options for those systems under the profile
identified by the `PROFILE` configuration key. We do not handle AWS-specific configuration
options in our configuration files.
identified by `hackillinois-api`. Be sure to set the `AWS` configuration key to `1` and
add the key `AWS_PROFILE` to your configuration with your corresponding profile name.

#### Considerations

Not all configuration options must be set during development (although all options should
Not all configuration options must be set during development (but all options _should_
be set in production). When certain keys are left empty, the API determines whether
or not it can use a local alternative or a default value at startup. Here are some
considerations that will help you determine which keys to set as you develop:

* Anyone contributing to a feature that involves email transmissions
will need to set the `HACKILLINOIS_MAIL_KEY` to a valid SparkPost API key.
* Anyone contributing to a feature that involves any AWS products will need to set
up an AWS shared credentials file (see above)

Note that this API is targeted for hosting via AWS, so any AWS-specific settings
(e.g. those in IAM roles) are used by this API before settings in any environment
variables or other credentials files.
or not it can use a local alternative or a default value at startup.

## Installation

Expand Down
19 changes: 0 additions & 19 deletions api/aws.js

This file was deleted.

84 changes: 39 additions & 45 deletions api/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,9 @@ const DEVELOPMENT_IDENTIFIER = 'development';
const PRODUCTION_IDENTIFIER = 'production';
const TEST_IDENTIFIER = 'test';

var environment = process.env.NODE_ENV;

var secret = process.env.HACKILLINOIS_SECRET || undefined;
var superuserEmail = process.env.HACKILLINOIS_SUPERUSER_EMAIL || undefined;
var superuserPassword = process.env.HACKILLINOIS_SUPERUSER_PASSWORD || undefined;
var mailApiKey = process.env.HACKILLINOIS_MAIL_KEY || undefined;

var isDevelopment = environment === DEVELOPMENT_IDENTIFIER;
var isProduction = environment === PRODUCTION_IDENTIFIER;
var isTest = environment === TEST_IDENTIFIER;

var exit = false;
if (!(isProduction || isDevelopment || isTest)) {
exit = true;
console.error("error: set NODE_ENV to '%s', '%s', or '%s'", PRODUCTION_IDENTIFIER, DEVELOPMENT_IDENTIFIER, TEST_IDENTIFIER);
} if (!superuserEmail) {
exit = true;
console.error("error: set configuration key 'HACKILLINOIS_SUPERUSER_EMAIL' to the desired admin email");
} if (!superuserPassword) {
exit = true;
console.error("error: set configuration key 'HACKILLINOIS_SUPERUSER_PASSWORD' to a secure, random string");
} if (!secret) {
exit = true;
console.error("error: set configuration key 'HACKILLINOIS_SECRET' to a secure, random string");
} if (isProduction && !mailApiKey) {
exit = true;
console.error("error: set configuration key 'HACKILLINOIS_MAIL_KEY' to the mailing provider's API key");
}
if (exit) {
console.error("error: environment incomplete. shutting down...");
process.exit();
}

var config = {};
config.auth = {};
config.auth = { };
config.aws = { defaults: {} };
config.database = {};
config.database.primary = { pool: {} };
config.mail = {};
Expand All @@ -50,21 +18,27 @@ config.storage = {};
config.superuser = {};
config.token = { expiration: {} };

config.isProduction = isProduction;
config.isDevelopment = isDevelopment;
config.isTest = isTest;
config.environment = environment;
config.secret = secret;
config.environment = process.env.NODE_ENV;
config.isProduction = (config.environment === PRODUCTION_IDENTIFIER);
config.isDevelopment = (config.environment === DEVELOPMENT_IDENTIFIER);
config.isTest = (config.environment === TEST_IDENTIFIER);
config.id = process.env.HACKILLINOIS_ID;
config.secret = process.env.HACKILLINOIS_SECRET;
config.port = process.env.HACKILLINOIS_PORT;
config.profile = process.env.PROFILE;

config.superuser.email = superuserEmail;
config.superuser.password = superuserPassword;
config.superuser.email = process.env.HACKILLINOIS_SUPERUSER_EMAIL;
config.superuser.password = process.env.HACKILLINOIS_SUPERUSER_PASSWORD;

config.auth.secret = config.secret;
config.auth.header = 'Authorization';
config.auth.expiration = '7d';

var sharedAWSCreds = new (require('aws-sdk').SharedIniFileCredentials)();
config.aws.enabled = (process.env.AWS && !!parseInt(process.env.AWS));
config.aws.defaults.credentials = (!!sharedAWSCreds.accessKeyId) ? sharedAWSCreds : undefined;
config.aws.defaults.region = 'us-east-1';
config.aws.defaults.sslEnabled = true;

config.token.expiration.DEFAULT = '7d';
config.token.expiration.AUTH = config.token.expiration.DEFAULT;

Expand All @@ -77,13 +51,33 @@ config.database.primary.pool.min = 0;
config.database.primary.pool.max = 7500;
config.database.primary.pool.idleTimeout = '5s';

config.mail.key = mailApiKey;
config.mail.key = process.env.HACKILLINOIS_MAIL_KEY;
config.mail.sinkhole = '.sink.sparkpostmail.com';
config.mail.whitelistedDomains = ['@hackillinois.org'];
config.mail.whitelistedLists = ['test'];

config.logs.groupName = (isDevelopment) ? 'api' : 'api-dev';
config.logs.streamPrefix = 'instances';
config.logs.groupName = (!config.isProduction) ? 'api-dev' : 'api';

config.storage.bucketExtension = (!config.isProduction) ? '-development' : '-2017';

config.storage.bucketExtension = (isDevelopment) ? '-development' : '-2017';
var exit = true;
if (!(config.isProduction || config.isDevelopment || config.isTest)) {
console.error("error: set NODE_ENV to '%s', '%s', or '%s'", PRODUCTION_IDENTIFIER, DEVELOPMENT_IDENTIFIER, TEST_IDENTIFIER);
} else if (!config.superuser.email) {
console.error("error: set configuration key 'HACKILLINOIS_SUPERUSER_EMAIL' to the desired admin email");
} else if (!config.superuser.password) {
console.error("error: set configuration key 'HACKILLINOIS_SUPERUSER_PASSWORD' to a secure, random string");
} else if (!config.secret) {
console.error("error: set configuration key 'HACKILLINOIS_SECRET' to a secure, random string");
} else if (config.isProduction && !config.mail.key) {
console.error("error: set configuration key 'HACKILLINOIS_MAIL_KEY' to the mailing provider's API key");
} else {
exit = false;
}
if (exit) {
console.error("fatal: environment incomplete. shutting down...");
process.exit();
}

module.exports = config;
15 changes: 5 additions & 10 deletions api/database.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
var logger = require('./logging');
var config = require('./config');
var logger = require('./logging');

var Bookshelf = require('bookshelf');
var Knex = require('knex');
var milliseconds = require('ms');

var KNEX_CONFIG = {
Expand All @@ -22,10 +20,12 @@ var KNEX_CONFIG = {
};

function DatabaseManager() {
this._knex = Knex(KNEX_CONFIG);
this._knex = require('knex')(KNEX_CONFIG);

this._bookshelf = Bookshelf(this._knex);
this._bookshelf = require('bookshelf')(this._knex);
this._bookshelf.plugin('pagination');

logger.info("connected to database as %s", config.database.primary.user);
}

DatabaseManager.prototype.constructor = DatabaseManager;
Expand All @@ -37,9 +37,4 @@ DatabaseManager.prototype.connection = function () {
return this._knex;
};

if (!config.isTest) {
// do not say this when the datastore is mocked
logger.info("connected to database as %s", config.database.primary.user);
}

module.exports = new DatabaseManager();
15 changes: 3 additions & 12 deletions api/logging.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@ var winston = require("winston");
var WinstonCloudwatch = require("winston-cloudwatch");

var config = require('./config');
var client = require('./aws');
var files = require('./files');

var TEMP_INSTANCE_ID = 'instanceid';

var transports = [];
if (client.isEnabled && config.isProduction) {
if (config.isProduction && config.aws.enabled) {
var cloudwatchTransport = new WinstonCloudwatch({
logGroupName: config.logs.groupName,
logStreamName: function() {
// keeps streams separated by instance and date
// TODO add instance to string once metadata is available

var date = new Date().toISOString().split('T')[0];
return date + '-' + TEMP_INSTANCE_ID;
},
awsRegion: 'us-east-1', // TODO switch this to the client.config.region
logStreamName: config.logs.streamPrefix + '/' + config.logs.groupName + '/' + config.id,
awsRegion: config.aws.defaults.region,
json: true
});

Expand Down
9 changes: 5 additions & 4 deletions api/v1/services/StorageService.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* jshint esversion: 6 */

var client = require('../../aws');
var client = require('aws-sdk');
var config = require('../../config');
var files = require('../../files');
var errors = require('../errors');
Expand All @@ -10,6 +10,7 @@ var uuid = require('node-uuid');
var _Promise = require('bluebird');
var _ = require('lodash');

client.config.update(config.aws.defaults);
var remote = new client.S3();

const CLIENT_NAME = "AWS_S3";
Expand Down Expand Up @@ -173,7 +174,7 @@ module.exports.createUpload = function (owner, params) {
* @throws {ExternalProviderError} when the upload fails any imposed validations
*/
module.exports.persistUpload = function (upload, file) {
if (!client.isEnabled) {
if (!config.aws.enabled) {
return _handleDisabledUpload(upload, file);
}
return _handleUpload(upload, file);
Expand All @@ -188,7 +189,7 @@ module.exports.persistUpload = function (upload, file) {
* @throws {ExternalProviderError} when the client throws an error
*/
module.exports.getUpload = function (upload) {
if (!client.isEnabled) {
if (!config.aws.enabled) {
return _handleDisabledRetrieval(upload);
}
return _handleRetrieval(upload);
Expand All @@ -203,7 +204,7 @@ module.exports.getUpload = function (upload) {
* @throws {ExternalProviderError} when the client throws an error
*/
module.exports.removeUpload = function (upload) {
if (!client.isEnabled) {
if (!config.aws.enabled) {
return _handleDisabledRemoval(upload);
}
return _handleRemoval(upload);
Expand Down
2 changes: 1 addition & 1 deletion config/dev.config.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
###############################################################################
#ENV AND PORTS
NODE_ENV=development
PROFILE=hackillinois-api
HACKILLINOIS_ID=instance0
HACKILLINOIS_PORT=8080

#API KEYS AND PASSWORDS
Expand Down
21 changes: 11 additions & 10 deletions config/prod.config.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
###############################################################################
#ENV AND PORTS
NODE_ENV=production
PROFILE=hackillinois-api
HACKILLINOIS_PORT=8080
AWS=1
HACKILLINOIS_ID=$PROD_INSTANCE_ID
HACKILLINOIS_PORT=$PROD_PORT

#API KEYS AND PASSWORDS
HACKILLINOIS_SECRET=
HACKILLINOIS_SUPERUSER_EMAIL=
HACKILLINOIS_SUPERUSER_PASSWORD=
HACKILLINOIS_MAIL_KEY=
HACKILLINOIS_SECRET=?
HACKILLINOIS_SUPERUSER_EMAIL=?
HACKILLINOIS_SUPERUSER_PASSWORD=?
HACKILLINOIS_MAIL_KEY=?

#DATABASE
DB_NAME=$PROD_DB_NAME
DB_HOSTNAME=127.0.0.1
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=
DB_HOSTNAME=$PROD_DB_HOST
DB_PORT=$PROD_DB_PORT
DB_USERNAME=$PROD_DB_USER
DB_PASSWORD=$PROD_DB_PASSWORD
4 changes: 2 additions & 2 deletions config/test.config.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
###############################################################################
#ENV AND PORTS
NODE_ENV=test
PROFILE=hackillinois-api
HACKILLINOIS_ID=instance0
HACKILLINOIS_PORT=8080

#API KEYS AND PASSWORDS
HACKILLINOIS_SECRET=VERY_SPECIAL_KEY
[email protected]
HACKILLINOIS_SUPERUSER_PASSWORD=ABCD1234!
HACKILLINOIS_MAIL_KEY=
HACKILLINOIS_MAIL_KEY=
Loading

0 comments on commit fe28671

Please sign in to comment.