diff --git a/README.md b/README.md
index 35b9411..b12b3c4 100644
--- a/README.md
+++ b/README.md
@@ -2,70 +2,197 @@
> A database-driven Greenlock storage plugin with wildcard support.
+## Features
+
+* Many [Supported SQL Databases](http://docs.sequelizejs.com/manual/getting-started.html)
+ * [x] PostgreSQL (**best**)
+ * [x] SQLite3 (**easiest**)
+ * [x] Microsoft SQL Server (mssql)
+ * [x] MySQL, MariaDB
+* Works on all platforms
+ * [x] Mac, Linux, VPS
+ * [x] AWS, Heroku, Akkeris, Docker
+ * [x] Windows
+
## Usage
-To use, provide this Greenlock storage plugin as the `store` attribute when you
-invoke `create`.
+To use, provide this Greenlock storage plugin as the `store` option when you
+invoke `create`:
```js
-greenlock.create({
- store: require('le-store-sequelize')
+Greenlock.create({
+ store: require('greenlock-store-sequelize')
+ ...
});
```
## Configuration
-### Defaults
+SQLite3 (default)
-No configuration is required. By default, you'll get a baked-in Sequelize
-database running [sqlite3](https://www.npmjs.com/package/sqlite3).
+SQLite3 is the default database, however, since it has a large number of dependencies
+and may require a native module to be built, you must explicitly install
+[sqlite3](https://www.npmjs.com/package/sqlite3):
-### Database Connection
+```bash
+npm install --save sqlite3
+```
-Without `config.dbOptions`, the baked-in sequelize object uses sqlite3 with
-defaults. If `config.dbOptions` is provided, you can configure the database
-connection per the Sequelize documentation.
+The default db file will be written wherever Greenlock's `configDir` is set to,
+which is probably `~/acme` or `~/letsencrypt`.
-If a dialect other than sqlite3 is used, dependencies will need to be
-installed.
+```bash
+~/acme/db.sqlite3
+```
-```javascript
-greenlock.create({
- store: require('le-store-sequelize')({
- dbConfig: {
- username: 'mysqluser',
- password: 'mysqlpassword',
- database: 'mysqldatabase,
- host: '127.0.0.1',
- dialect: 'mysql'
+If you wish to set special options you may do so by passing a pre-configured `Sequelize` instance:
+
+```js
+var Sequelize = require('sequelize');
+var db = new Sequelize({ dialect: 'sqlite', storage: '/Users/me/acme/db.sqlite3' });
+
+Greenlock.create({
+ store: require('greenlock-store-sequelize').create({ db: db })
+ ...
+});
+```
+
+
+PostgreSQL, SQL Server, and lesser databases...
+
+The general format of a DATABASE_URL is something like this:
+
+> `schema://user:pass@server:port/service?option=foo`
+
+For example:
+
+> `postgres://aj:secret123@127.0.0.1:5432/greenlock`
+
+For each database the exact format may be slightly different:
+
+* `postgres://user:pass@hostname:port/database?option=foo`
+* `sqlserver://user:pass@datasource:port/instance/catalog?database=dbname` (mssql)
+* `mysql://user:pass@hostname:port/database?option=foo`
+* `mariadb://user:pass@hostname:port/database?option=foo`
+
+There's also a way to specify objects instead of using the standard connection strings.
+
+See the next section for more information.
+
+
+Database URLs / Connection Strings
+You may use database URLs (also known as 'connection strings') to initialize sequelize:
+
+```js
+var dbUrl = 'postgres://user:pass@hostname:port/database';
+
+Greenlock.create({
+ store: require('greenlock-store-sequelize').create({ storeDatabaseUrl: dbUrl })
+ ...
+});
+```
+
+If you need to use **custom options**, just instantiate sequelize directly:
+
+```js
+var Sequelize = require('sequelize');
+var db = new Sequelize('postgres://user:pass@hostname:port/database');
+
+Greenlock.create({
+ store: require('greenlock-store-sequelize').create({ db: db })
+ ...
+});
+```
+
+See the [Sequelize Getting Started](http://docs.sequelizejs.com/manual/getting-started.html) docs for more info
+on database options for sequelize.
+
+
+Environment variables (AWS, Docker, Heroku, Akkeris)
+If your database connection string is in an environment variable,
+you would use the usual standard for your platform.
+
+For example, if you're using Heroku, Akkeris, or Docker you're
+database connection string is probably `DATABASE_URL`, so you'd do something like this:
+
+```js
+var Sequelize = require('sequelize');
+var databaseUrl = process.env['DATABASE_URL'];
+var db = new Sequelize(databaseUrl);
+
+Greenlock.create({
+ store: require('greenlock-store-sequelize').create({ db: db })
+ ...
+});
+```
+
+
+Table Prefixes
+The default table names are as follows:
+
+* Keypair
+* Domain
+* Certificate
+* Chain
+
+If you'd like to add a table name prefix or define a specific schema within the database (PostgreSQL, SQL Server),
+you can do so like this:
+
+```js
+var Sequelize = require('sequelize');
+var databaseUrl = process.env['DATABASE_URL'];
+var db = new Sequelize(databaseUrl, {
+ hooks: {
+ beforeDefine: function (columns, model) {
+ model.tableName = 'MyPrefix' + model.name.plural;
+ //model.schema = 'public';
+ }
}
- })
+});
+
+Greenlock.create({
+ store: require('greenlock-store-sequelize').create({ db: db })
+ ...
});
```
+
-The database can also be configured using an env variable.
+## Table Structure
-```javascript
-greenlock.create({
- store: require('greenlock-store-sequelize')({
- dbConfig: {
- use_env_variable: 'DB_URL'
- }
- })
-});
-```
-
-### Custom Database Object
-
-If you already have a Sequelize object, you can pass that in as `config.db`,
-circumventing the baked-in database entirely.
-
-```javascript
-var db = require('./db'); // your db
-
-greenlock.create({
- store: require('le-store-sequelize')({
- db
- })
-});
+This is the table structure that's created.
+
+```sql
+CREATE TABLE `Keypairs` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `xid` VARCHAR(255) UNIQUE,
+ `content` TEXT,
+ `createdAt` DATETIME NOT NULL,
+ `updatedAt` DATETIME NOT NULL);
+
+CREATE TABLE `Domains` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `subject` VARCHAR(255) UNIQUE,
+ `altnames` TEXT,
+ `createdAt` DATETIME NOT NULL,
+ `updatedAt` DATETIME NOT NULL);
+
+CREATE TABLE `Certificates` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `subject` VARCHAR(255) UNIQUE,
+ `cert` TEXT,
+ `issuedAt` DATETIME,
+ `expiresAt` DATETIME,
+ `altnames` TEXT,
+ `chain` TEXT,
+ `createdAt` DATETIME NOT NULL,
+ `updatedAt` DATETIME NOT NULL);
+
+CREATE TABLE `Chains` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `xid` VARCHAR(255) UNIQUE,
+ `content` TEXT,
+ `createdAt` DATETIME NOT NULL,
+ `updatedAt` DATETIME NOT NULL,
+ `CertificateId` INTEGER REFERENCES
+ `Certificates` (`id`) ON DELETE SET NULL ON UPDATE CASCADE);
```
diff --git a/db/index.js b/db/index.js
index 89495db..a804e0d 100644
--- a/db/index.js
+++ b/db/index.js
@@ -1,49 +1,25 @@
'use strict';
-var fs = require('fs');
var path = require('path');
-var basename = path.basename(__filename);
-var Sequelize = require('sequelize');
var sync = require('../sync.js');
-module.exports = function (config) {
+module.exports = function (sequelize) {
var db = {};
- db.Sequelize = Sequelize;
-
- if (!config) {
- config = {
- dialect: "sqlite",
- storage: "./db.sqlite"
- };
- }
-
- if (config.use_env_variable) {
- db.sequelize = new db.Sequelize(process.env[config.use_env_variable], config);
- }
- else {
- db.sequelize = new db.Sequelize(config.database, config.username, config.password, config);
- }
-
- fs.readdirSync(__dirname).filter(function (file) {
- return ('.' !== file[0]) && (file !== basename) && (file.slice(-3) === '.js');
- }).forEach(function (file) {
- var model = db.sequelize['import'](path.join(__dirname, file));
+ [ 'keypair.js'
+ , 'domain.js'
+ , 'certificate.js'
+ , 'chain.js'
+ ].forEach(function (file) {
+ var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function (modelName) {
- if (db[modelName].associate) {
- db[modelName].associate(db);
- }
+ db[modelName].associate(db);
});
- var synced = false;
- if (!synced) {
- return sync(db).then(function () {
- synced = true;
- return db;
- });
- }
- return Promise.resolve(db);
+ return sync(db).then(function () {
+ return db;
+ });
};
diff --git a/greenlock-store-sequelize.js b/greenlock-store-sequelize.js
index 2edd794..5631e7d 100644
--- a/greenlock-store-sequelize.js
+++ b/greenlock-store-sequelize.js
@@ -6,21 +6,30 @@ module.exports.create = function (config={}) {
accounts: {},
certificates: {}
};
+ var Sequelize;
+ var sequelize = config.db;
+ var confDir = config.configDir || (require('os').homedir() + '/acme');
// The user can provide their own db, but if they don't, we'll use the
// baked-in db.
- if (!config.db) {
+ if (!sequelize) {
// If the user provides options for the baked-in db, we'll use them. If
// they don't, we'll use the baked-in db with its defaults.
- config.db = require('./db')(config.dbConfig || null);
- }
- else {
- // This library expects config.db to resolve the db object. We'll ensure
- // that this is the case with the provided db, as it was with the baked-in
- // db.
- config.db = Promise.resolve(config.db);
+ Sequelize = require('sequelize');
+ if (config.storeDatabaseUrl) {
+ sequelize = new Sequelize(config.storeDatabaseUrl);
+ } else {
+ sequelize = new Sequelize({ dialect: 'sqlite', storage: confDir + '/db.sqlite3' });
+ }
}
+ // This library expects config.db to resolve the db object. We'll ensure
+ // that this is the case with the provided db, as it was with the baked-in
+ // db.
+ config.db = Promise.resolve(sequelize).then(function (sequelize) {
+ return require('./db')(sequelize);
+ });
+
store.certificates.check = function (opts) {
return config.db.then(function (db) {
return db.Certificate.findOne({
@@ -49,7 +58,7 @@ module.exports.create = function (config={}) {
err.code = 'ENOENT';
throw err;
}).catch(function (err) {
- if (err.code == 'ENOENT') {
+ if (err.code === 'ENOENT') {
return null;
}
throw err;
@@ -77,7 +86,7 @@ module.exports.create = function (config={}) {
err.code = 'ENOENT';
throw err;
}).catch(function (err) {
- if (err.code == 'ENOENT') {
+ if (err.code === 'ENOENT') {
return null;
}
throw err;
@@ -119,7 +128,7 @@ module.exports.create = function (config={}) {
err.code = 'ENOENT';
throw err;
}).catch(function (err) {
- if (err.code == 'ENOENT') {
+ if (err.code === 'ENOENT') {
return null;
}
throw err;
diff --git a/sync.js b/sync.js
index 7544b20..7155806 100644
--- a/sync.js
+++ b/sync.js
@@ -6,17 +6,10 @@ function sync(db) {
function next() {
var modelName = keys.shift();
if (!modelName) { return; }
- if (isModel(modelName)) {
- return db[modelName].sync().then(next);
- }
- return next();
+ return db[modelName].sync().then(next);
}
return Promise.resolve().then(next);
}
-function isModel(key) {
- return !(['sequelize','Sequelize'].includes(key));
-}
-
module.exports = sync;