greenlock-manager-test.js
A simple test suite for Greenlock v3 manager plugins.
Greenlock Manager
A Greenlock Manager is responsible for tracking which domains belong on a certificate, when they are scheduled for renewal, and if they have been deleted.
It consists of two required functions:
;
;
However, if you implement find({ subject, servernames, renewBefore })
(optional),
you don't have to implement get()
.
Usage Details
# How to use your pluginThe Right Way:
npm install --save greenlacknpx greenlock init --manager ./path-or-npm-name.js --manager-xxxx 'sets xxxx' --manager-yyyy 'set yyyy'
That creates a .greenlockrc
, which is essentially the same as doing this:
var Greenlock = ;var greenlock = Greenlock;
Why no require?
Okay, so you expect it to look like this:
var Greenlock = ;var greenlock = Greenlock;
NOPE!
Greenlock is designed to so that the CLI tools, Web API, and JavaScript API can all work interdepedently, indpendently.
Therefore the configuration has to go into serializable JSON rather than executable JavaScript.
Quick Start
If you want to write a manager, the best way to start is by using one of the provided templates.
npm install --save-dev greenlock-manager-testnpx greenlock-manager-init
It will generate a bare bones manager that passes the tests, (skipping all optional features), and a test file:
manager.js
"use strict"; var Manager = moduleexports;var db = {}; Manager { var manager = {}; // // REQUIRED (basic issuance) // // Get manager { // Required: find the certificate with the subject of `servername` // Optional (multi-domain certs support): find a certificate with `servername` as an altname // Optional (wildcard support): find a certificate with `wildname` as an altname // { subject, altnames, renewAt, deletedAt, challenges, ... } return dbservername || dbwildname; }; // Set manager { // { subject, altnames, renewAt, deletedAt } // Required: updated `renewAt` and `deletedAt` for certificate matching `subject` var site = dboptssubject || {}; dboptssubject = Object; return null; }; // // Optional (Fully Automatic Renewal) // /* manager.find = async function(opts) { // { subject, servernames, altnames, renewBefore } return [{ subject, altnames, renewAt, deletedAt }]; }; //*/ // // Optional (Special Remove Functionality) // The default behavior is to set `deletedAt` // /* manager.remove = async function(opts) { return mfs.remove(opts); }; //*/ // // Optional (special settings save) // Implemented here because this module IS the fallback // /* manager.defaults = async function(opts) { if (opts) { return setDefaults(opts); } return getDefaults(); }; //*/ // // Optional (for common deps and/or async initialization) // /* manager.init = async function(deps) { manager.request = deps.request; return null; }; //*/ return manager;};
manager.test.js
"use strict"; var Tester = ; var Manager = ;var config = configFile: "greenlock-manager-test.delete-me.json"; Tester ;
node manager.test.js
PASS: get({ servername, wildname })PASS: set({ subject }) Optional Feature Support:✘ (NO) Multiple Domains per Certificate✘ (NO) Wildcard Certificates✘ (NO) Fully Automatic Renewal
Optional Features
If you're publishing a module to the community, you should implement the full test suite (and it's not that hard).
If you're only halfway through, you should note which features are supported and which aren't.
;;; // as getter
find()
is used to get the full list of sites, for continuous fully automatic renewal.defaults()
exists so that the global config can be saved in the same place as the per-site config.- a proper
get()
should be able to search not just primary domains, but altnames as well.
Additionally, you're manager may need an init or a real delete - rather than just using set({ deletedAt })
:
;;
Full Implementation
The Right Way™
If you want to publish a module to the community you should do a slightly better job:
moduleexports { var manager = {}; // add some things to... wherever you save things manager { // You can see in the tests a sample of common values, // but you don't really need to worry about it. var subject = siteConfigsubject; // Cherry pick what you like for indexing / search, and JSONify the rest return ; }; // find the things you've saved before manager { return ; } manager { var results = ; var gotten = {}; if subject var site = await ; if site && sitesubject === subject return site; if severnames return await Promiseallservernames; } return ; }; // delete a site config manager { // set deletedAt to a value, or actually delete it - however you like return ; }; // get / set global things manager { if !options return ; return ; }; // optional, if you need it manager { // a place to do some init, if you need it return ; // Also, `deps` will have some common dependencies // than many modules need, such as `request`. // This cuts down on stray dependencies, and helps // with browser compatibility. request = depsrequest; };};