2021-11-29 16:24:39 -05:00
|
|
|
# type: ignore
|
2019-03-01 16:18:06 -05:00
|
|
|
"""
|
|
|
|
|
General conftest for pytest execution of all integration tests lying
|
|
|
|
|
in the certbot_integration tests package.
|
|
|
|
|
As stated by pytest documentation, conftest module is used to set on
|
|
|
|
|
for a directory a specific configuration using built-in pytest hooks.
|
|
|
|
|
|
|
|
|
|
See https://docs.pytest.org/en/latest/reference.html#hook-reference
|
|
|
|
|
"""
|
|
|
|
|
import contextlib
|
|
|
|
|
import subprocess
|
2019-12-09 15:50:20 -05:00
|
|
|
import sys
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
from certbot_integration_tests.utils import acme_server as acme_lib
|
2020-11-17 03:27:27 -05:00
|
|
|
from certbot_integration_tests.utils import dns_server as dns_lib
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def pytest_addoption(parser):
|
|
|
|
|
"""
|
|
|
|
|
Standard pytest hook to add options to the pytest parser.
|
|
|
|
|
:param parser: current pytest parser that will be used on the CLI
|
|
|
|
|
"""
|
|
|
|
|
parser.addoption('--acme-server', default='pebble',
|
2021-12-13 13:42:15 -05:00
|
|
|
choices=['boulder-v2', 'pebble'],
|
|
|
|
|
help='select the ACME server to use (boulder-v2, pebble), '
|
|
|
|
|
'defaulting to pebble')
|
2020-11-17 03:27:27 -05:00
|
|
|
parser.addoption('--dns-server', default='challtestsrv',
|
|
|
|
|
choices=['bind', 'challtestsrv'],
|
|
|
|
|
help='select the DNS server to use (bind, challtestsrv), '
|
|
|
|
|
'defaulting to challtestsrv')
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def pytest_configure(config):
|
|
|
|
|
"""
|
|
|
|
|
Standard pytest hook used to add a configuration logic for each node of a pytest run.
|
|
|
|
|
:param config: the current pytest configuration
|
|
|
|
|
"""
|
2021-03-23 14:29:01 -04:00
|
|
|
if not hasattr(config, 'workerinput'): # If true, this is the primary node
|
2019-03-01 16:18:06 -05:00
|
|
|
with _print_on_err():
|
2020-11-17 03:27:27 -05:00
|
|
|
_setup_primary_node(config)
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def pytest_configure_node(node):
|
|
|
|
|
"""
|
|
|
|
|
Standard pytest-xdist hook used to configure a worker node.
|
|
|
|
|
:param node: current worker node
|
|
|
|
|
"""
|
2021-03-23 14:29:01 -04:00
|
|
|
node.workerinput['acme_xdist'] = node.config.acme_xdist
|
|
|
|
|
node.workerinput['dns_xdist'] = node.config.dns_xdist
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
|
def _print_on_err():
|
|
|
|
|
"""
|
|
|
|
|
During pytest-xdist setup, stdout is used for nodes communication, so print is useless.
|
|
|
|
|
However, stderr is still available. This context manager transfers stdout to stderr
|
|
|
|
|
for the duration of the context, allowing to display prints to the user.
|
|
|
|
|
"""
|
|
|
|
|
old_stdout = sys.stdout
|
|
|
|
|
sys.stdout = sys.stderr
|
|
|
|
|
try:
|
|
|
|
|
yield
|
|
|
|
|
finally:
|
|
|
|
|
sys.stdout = old_stdout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _setup_primary_node(config):
|
|
|
|
|
"""
|
|
|
|
|
Setup the environment for integration tests.
|
2020-11-17 03:27:27 -05:00
|
|
|
|
|
|
|
|
This function will:
|
2020-01-17 12:55:51 -05:00
|
|
|
- check runtime compatibility (Docker, docker-compose, Nginx)
|
2019-03-01 16:18:06 -05:00
|
|
|
- create a temporary workspace and the persistent GIT repositories space
|
2020-11-17 03:27:27 -05:00
|
|
|
- configure and start a DNS server using Docker, if configured
|
2019-03-01 16:18:06 -05:00
|
|
|
- configure and start paralleled ACME CA servers using Docker
|
2020-11-17 03:27:27 -05:00
|
|
|
- transfer ACME CA and DNS servers configurations to pytest nodes using env variables
|
|
|
|
|
|
|
|
|
|
This function modifies `config` by injecting the ACME CA and DNS server configurations,
|
|
|
|
|
in addition to cleanup functions for those servers.
|
|
|
|
|
|
|
|
|
|
:param config: Configuration of the pytest primary node. Is modified by this function.
|
2019-03-01 16:18:06 -05:00
|
|
|
"""
|
|
|
|
|
# Check for runtime compatibility: some tools are required to be available in PATH
|
[Windows|Linux] Launch integration tests on Pebble without Docker (#7157)
This PR is a part of the actions necessary to make Certbot-CI work on Windows, in order to execute the integration tests on this platform.
Following #7156, this PR changes how the integration tests are setup against Pebble to not need Docker anymore.
As a reminder, one can check #7156 and letsencrypt/pebble#240 to see the rationale about why using Docker is a problem to run the integration tests on Windows.
Basically, this PR executes directly Pebble using its executable, since it is build using Go, and Go produces self-contained executable that can run without any installation on Linux and on Windows. During the integration tests setup, Certbot-CI will get the Pebble (and Challtestsrv) executables for the defined target version on the GitHub releases. The binaries are persisted on the filesystem, so it is not needed to download them again on the second integration tests execution. Nonetheless, we are talking about 20MB of executables.
Since the setup needs to hold a state, I also took this occasion to refactor the acme_server, in order to use on object oriented approach and improve the readability/maintainability.
Once this PR and #7156 are merged, Docker will not be needed anymore for the main integration tests usecase, that is to use Pebble.
* Complete process
* Fix nginx cert path
* Check conditionnally docker
* Update gitignore, fix apacheconftest
* Full object
* Carriage return
* Move to official v2.1.0 of pebble
* Fix name
* Update acme_server.py
* Relaunch CI
* Update certbot-ci/certbot_integration_tests/utils/acme_server.py
Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>
* Update certbot-ci/certbot_integration_tests/utils/acme_server.py
Co-Authored-By: Brad Warren <bmw@users.noreply.github.com>
* Update docstring
* Update documentation
* Configure a stdout to ACMEServer
* Map all process through defined stdout
* Remove unused variable
* Handle using signals
* Use failsafe entering context
* Remove failsafe rmtree, that is not needed anymore
2019-07-10 17:29:57 -04:00
|
|
|
if 'boulder' in config.option.acme_server:
|
|
|
|
|
try:
|
|
|
|
|
subprocess.check_output(['docker', '-v'], stderr=subprocess.STDOUT)
|
|
|
|
|
except (subprocess.CalledProcessError, OSError):
|
|
|
|
|
raise ValueError('Error: docker is required in PATH to launch the integration tests on'
|
|
|
|
|
'boulder, but is not installed or not available for current user.')
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
subprocess.check_output(['docker-compose', '-v'], stderr=subprocess.STDOUT)
|
|
|
|
|
except (subprocess.CalledProcessError, OSError):
|
2020-12-16 14:34:12 -05:00
|
|
|
raise ValueError(
|
|
|
|
|
'Error: docker-compose is required in PATH to launch the integration tests, '
|
|
|
|
|
'but is not installed or not available for current user.'
|
|
|
|
|
)
|
2019-03-01 16:18:06 -05:00
|
|
|
|
|
|
|
|
# Parameter numprocesses is added to option by pytest-xdist
|
|
|
|
|
workers = ['primary'] if not config.option.numprocesses\
|
|
|
|
|
else ['gw{0}'.format(i) for i in range(config.option.numprocesses)]
|
|
|
|
|
|
2020-11-17 03:27:27 -05:00
|
|
|
# If a non-default DNS server is configured, start it and feed it to the ACME server
|
|
|
|
|
dns_server = None
|
|
|
|
|
acme_dns_server = None
|
|
|
|
|
if config.option.dns_server == 'bind':
|
|
|
|
|
dns_server = dns_lib.DNSServer(workers)
|
|
|
|
|
config.add_cleanup(dns_server.stop)
|
|
|
|
|
print('DNS xdist config:\n{0}'.format(dns_server.dns_xdist))
|
|
|
|
|
dns_server.start()
|
|
|
|
|
acme_dns_server = '{}:{}'.format(
|
|
|
|
|
dns_server.dns_xdist['address'],
|
|
|
|
|
dns_server.dns_xdist['port']
|
|
|
|
|
)
|
|
|
|
|
|
2019-03-01 16:18:06 -05:00
|
|
|
# By calling setup_acme_server we ensure that all necessary acme server instances will be
|
|
|
|
|
# fully started. This runtime is reflected by the acme_xdist returned.
|
2020-11-17 03:27:27 -05:00
|
|
|
acme_server = acme_lib.ACMEServer(config.option.acme_server, workers,
|
|
|
|
|
dns_server=acme_dns_server)
|
Add executable scripts to start certbot and acme server in certbot-ci (#7073)
During review of #6989, we saw that some of our test bash scripts were still used in the Boulder project in particular. It is about `tests/integration/_common.sh` in particular, to expose the `certbot_test` bash function, that is an appropriate way to execute a local version of certbot in test mode: define a custom server, remove several checks, full log and so on.
This PR is an attempt to assert this goal: exposing a new `certbot_test` executable for test purpose. More generally, this PR is about giving well suited scripts to quickly make manual tests against certbot without launching the full automated pytest suite.
The idea here is to leverage the existing logic in certbot-ci, and expose it as executable scripts. This is done thanks to the `console_scripts` entry of setuptools entrypoint feature, that install scripts in the `PATH`, when `pip install` is invoked, that delegate to specific functions in the installed packages.
Two scripts are defined this way:
* `certbot_test`: it executes certbot in test mode in a very similar way than the original `certbot_test` in `_common.sh`, by delegating to `certbot_integration_tests.utils.certbot_call:main`. By default this execution will target a pebble directory url started locally. The url, and also http-01/tls-alpn-01 challenge ports can be configured using ad-hoc environment variables. All arguments passed to `certbot_test` are transferred to the underlying certbot command.
* `acme_server`: it set up a fully running instance of an ACME server, ready for tests (in particular, all FQDN resolves to localhost in order to target a locally running `certbot_test` command) by delegating to `certbot_integration_tests.utils.acme_server:main`. The choice of the ACME server is given by the first parameter passed to `acme_server`, it can be `pebble`, `boulder-v1` or `boulder-v2`. The command keeps running on foreground, displaying the logs of the ACME server on stdout/stderr. The server is shut down and resources cleaned upon entering CTRL+C.
This two commands can be run also through the underlying python modules, that are executable.
Finally, a typical workflow on certbot side to run manual tests would be:
```
cd certbot
tools/venv.py
source venv/bin/activate
acme_server pebble &
certbot_test certonly --standalone -d test.example.com
```
On boulder side it could be:
```
# Follow certbot dev environment setup instructions, then ...
cd boulder
docker-compose run --use-aliases -e FAKE_DNS=172.17.0.1 --service-ports boulder ./start.py
SERVER=http://localhost:4001/directory certbot_test certonly --standalone -d test.example.com
```
* Configure certbot-ci to expose a certbot_test console script calling certbot in test mode against a local pebble instance
* Add a command to start pebble/boulder
* Use explicit start
* Add execution permission to acme_server
* Add a docstring to certbot_test function
* Change executable name
* Increase sleep to 3600s
* Implement a context manager to handle the acme server
* Add certbot_test workspace in .gitignore
* Add documentation
* Remove one function in context, split logic of certbot_test towards capturing non capturing
* Use an explicit an properly configured ACMEServer as handler.
* Add doc. Put constants.
2019-06-12 20:19:23 -04:00
|
|
|
config.add_cleanup(acme_server.stop)
|
|
|
|
|
print('ACME xdist config:\n{0}'.format(acme_server.acme_xdist))
|
|
|
|
|
acme_server.start()
|
2019-03-01 16:18:06 -05:00
|
|
|
|
2020-11-17 03:27:27 -05:00
|
|
|
config.acme_xdist = acme_server.acme_xdist
|
|
|
|
|
config.dns_xdist = dns_server.dns_xdist if dns_server else None
|