diff --git a/README.rst b/README.rst index 86d85ed1d..fac36dbd7 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,7 @@ Documentation: https://letsencrypt.readthedocs.org/ Software project: https://github.com/letsencrypt/lets-encrypt-preview -Notes for developers: CONTRIBUTING.rst_ +Notes for developers: CONTRIBUTING.md_ Main Website: https://letsencrypt.org/ @@ -91,4 +91,4 @@ email to client-dev+subscribe@letsencrypt.org) .. _Freenode: https://freenode.net .. _client-dev: https://groups.google.com/a/letsencrypt.org/forum/#!forum/client-dev -.. _CONTRIBUTING.rst: https://github.com/letsencrypt/lets-encrypt-preview/blob/master/CONTRIBUTING.rst +.. _CONTRIBUTING.md: https://github.com/letsencrypt/lets-encrypt-preview/blob/master/CONTRIBUTING.md diff --git a/docs/plugins.rst b/docs/plugins.rst index 552985aab..0451bfe3f 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -2,4 +2,18 @@ Plugins ======= -You can find an example in ``examples/plugins/`` directory. +Let's Encrypt client supports dynamic discovery of plugins through the +`setuptools entry points`_. This way you can, for example, create a +custom implementation of +`~letsencrypt.client.interfaces.IAuthenticator` or the +'~letsencrypt.client.interfaces.IInstaller' without having to +merge it with the core upstream source code. An example is provided in +``examples/plugins/`` directory. + +Please be aware though that as this client is still in a developer-preview +stage, the API may undergo a few changes. If you believe the plugin will be +beneficial to the community, please consider submitting a pull request to the +repo and we will update it with any necessary API changes. + +.. _`setuptools entry points`: + https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins diff --git a/letsencrypt/client/client.py b/letsencrypt/client/client.py index 09817cc21..c9723772a 100644 --- a/letsencrypt/client/client.py +++ b/letsencrypt/client/client.py @@ -1,15 +1,11 @@ """ACME protocol client class and helper functions.""" import logging import os -import pkg_resources import sys import Crypto.PublicKey.RSA import M2Crypto -import zope.interface.exceptions -import zope.interface.verify - from letsencrypt.acme import messages from letsencrypt.acme.jose import util as jose_util @@ -17,7 +13,6 @@ from letsencrypt.client import auth_handler from letsencrypt.client import client_authenticator from letsencrypt.client import crypto_util from letsencrypt.client import errors -from letsencrypt.client import interfaces from letsencrypt.client import le_util from letsencrypt.client import network from letsencrypt.client import reverter @@ -28,28 +23,6 @@ from letsencrypt.client.display import ops as display_ops from letsencrypt.client.display import enhancements -SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT = "letsencrypt.authenticators" -"""Setuptools entry point group name for Authenticator plugins.""" - - -def init_auths(config): - """Find (setuptools entry points) and initialize Authenticators.""" - auths = {} - for entrypoint in pkg_resources.iter_entry_points( - SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT): - auth_cls = entrypoint.load() - auth = auth_cls(config) - try: - zope.interface.verify.verifyObject(interfaces.IAuthenticator, auth) - except zope.interface.exceptions.BrokenImplementation: - logging.debug( - "%r object does not provide IAuthenticator, skipping", - entrypoint.name) - else: - auths[auth] = entrypoint.name - return auths - - class Client(object): """ACME protocol client. diff --git a/letsencrypt/scripts/main.py b/letsencrypt/scripts/main.py index 8b2c62935..3b4b7c10d 100644 --- a/letsencrypt/scripts/main.py +++ b/letsencrypt/scripts/main.py @@ -11,6 +11,8 @@ import sys import confargparse import zope.component +import zope.interface.exceptions +import zope.interface.verify import letsencrypt @@ -24,6 +26,28 @@ from letsencrypt.client.display import util as display_util from letsencrypt.client.display import ops as display_ops +SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT = "letsencrypt.authenticators" +"""Setuptools entry point group name for Authenticator plugins.""" + + +def init_auths(config): + """Find (setuptools entry points) and initialize Authenticators.""" + auths = {} + for entrypoint in pkg_resources.iter_entry_points( + SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT): + auth_cls = entrypoint.load() + auth = auth_cls(config) + try: + zope.interface.verify.verifyObject(interfaces.IAuthenticator, auth) + except zope.interface.exceptions.BrokenImplementation: + logging.debug( + "%r object does not provide IAuthenticator, skipping", + entrypoint.name) + else: + auths[auth] = entrypoint.name + return auths + + def create_parser(): """Create parser.""" parser = confargparse.ConfArgParser( @@ -134,7 +158,7 @@ def main(): # pylint: disable=too-many-branches, too-many-statements if not args.eula: display_eula() - all_auths = client.init_auths(config) + all_auths = init_auths(config) logging.debug('Initialized authenticators: %s', all_auths.values()) try: auth = client.determine_authenticator(all_auths.keys())