mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 19:14:54 +02:00
Mark semiprivate methods in configurator
This commit is contained in:
@@ -35,6 +35,12 @@ class NginxConfigurator(object):
|
|||||||
:ivar parser: Handles low level parsing
|
:ivar parser: Handles low level parsing
|
||||||
:type parser: :class:`~letsencrypt.client.plugins.nginx.parser`
|
:type parser: :class:`~letsencrypt.client.plugins.nginx.parser`
|
||||||
|
|
||||||
|
:ivar set save_files: Files that need to be saved
|
||||||
|
:ivar str save_notes: Human-readable config change notes
|
||||||
|
|
||||||
|
:ivar reverter: saves and reverts checkpoints
|
||||||
|
:type reverter: :class:`letsencrypt.client.reverter.Reverter`
|
||||||
|
|
||||||
:ivar tup version: version of Nginx
|
:ivar tup version: version of Nginx
|
||||||
:ivar list vhosts: All vhosts found in the configuration
|
:ivar list vhosts: All vhosts found in the configuration
|
||||||
(:class:`list` of
|
(:class:`list` of
|
||||||
@@ -55,11 +61,14 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.config = config
|
self.config = config
|
||||||
self.save_notes = ""
|
|
||||||
|
|
||||||
# Verify that all directories and files exist with proper permissions
|
# Verify that all directories and files exist with proper permissions
|
||||||
if os.geteuid() == 0:
|
if os.geteuid() == 0:
|
||||||
self.verify_setup()
|
self._verify_setup()
|
||||||
|
|
||||||
|
# Files to save
|
||||||
|
self.save_files = set()
|
||||||
|
self.save_notes = ""
|
||||||
|
|
||||||
# Add name_server association dict
|
# Add name_server association dict
|
||||||
self.assoc = dict()
|
self.assoc = dict()
|
||||||
@@ -76,6 +85,7 @@ class NginxConfigurator(object):
|
|||||||
self.reverter = reverter.Reverter(config)
|
self.reverter = reverter.Reverter(config)
|
||||||
self.reverter.recovery_routine()
|
self.reverter.recovery_routine()
|
||||||
|
|
||||||
|
# This is called in determine_authenticator and determine_installer
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
"""Prepare the authenticator/installer."""
|
"""Prepare the authenticator/installer."""
|
||||||
self.parser = parser.NginxParser(
|
self.parser = parser.NginxParser(
|
||||||
@@ -84,13 +94,14 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
# Set Version
|
# Set Version
|
||||||
if self.version is None:
|
if self.version is None:
|
||||||
self.version = self.get_version()
|
self.version = self._get_version()
|
||||||
|
|
||||||
# Get all of the available vhosts
|
# Get all of the available vhosts
|
||||||
self.vhosts = self.get_virtual_hosts()
|
self.vhosts = self._get_vhosts()
|
||||||
|
|
||||||
temp_install(self.config.nginx_mod_ssl_conf)
|
temp_install(self.config.nginx_mod_ssl_conf)
|
||||||
|
|
||||||
|
# Entry point in main.py for installing cert
|
||||||
def deploy_cert(self, domain, cert, key, cert_chain=None):
|
def deploy_cert(self, domain, cert, key, cert_chain=None):
|
||||||
"""Deploys certificate to specified virtual host.
|
"""Deploys certificate to specified virtual host.
|
||||||
|
|
||||||
@@ -154,7 +165,7 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
# Make sure vhost is enabled
|
# Make sure vhost is enabled
|
||||||
if not vhost.enabled:
|
if not vhost.enabled:
|
||||||
self.enable_site(vhost)
|
self._enable_site(vhost)
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
# Vhost parsing methods
|
# Vhost parsing methods
|
||||||
@@ -172,7 +183,6 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
# Allows for domain names to be associated with a virtual host
|
# Allows for domain names to be associated with a virtual host
|
||||||
# Client isn't using create_dn_server_assoc(self, dn, vh) yet
|
|
||||||
if target_name in self.assoc:
|
if target_name in self.assoc:
|
||||||
return self.assoc[target_name]
|
return self.assoc[target_name]
|
||||||
# Check for servernames/aliases for ssl hosts
|
# Check for servernames/aliases for ssl hosts
|
||||||
@@ -191,7 +201,7 @@ class NginxConfigurator(object):
|
|||||||
# Check for non ssl vhosts with servernames/aliases == "name"
|
# Check for non ssl vhosts with servernames/aliases == "name"
|
||||||
for vhost in self.vhosts:
|
for vhost in self.vhosts:
|
||||||
if not vhost.ssl and target_name in vhost.names:
|
if not vhost.ssl and target_name in vhost.names:
|
||||||
vhost = self.make_vhost_ssl(vhost)
|
vhost = self._make_vhost_ssl(vhost)
|
||||||
self.assoc[target_name] = vhost
|
self.assoc[target_name] = vhost
|
||||||
return vhost
|
return vhost
|
||||||
|
|
||||||
@@ -201,19 +211,6 @@ class NginxConfigurator(object):
|
|||||||
return vhost
|
return vhost
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def create_dn_server_assoc(self, domain, vhost):
|
|
||||||
"""Create an association between a domain name and virtual host.
|
|
||||||
|
|
||||||
Helps to choose an appropriate vhost
|
|
||||||
|
|
||||||
:param str domain: domain name to associate
|
|
||||||
|
|
||||||
:param vhost: virtual host to associate with domain
|
|
||||||
:type vhost: :class:`~letsencrypt.client.plugins.nginx.obj.VirtualHost`
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.assoc[domain] = vhost
|
|
||||||
|
|
||||||
def get_all_names(self):
|
def get_all_names(self):
|
||||||
"""Returns all names found in the Nginx Configuration.
|
"""Returns all names found in the Nginx Configuration.
|
||||||
|
|
||||||
@@ -243,7 +240,7 @@ class NginxConfigurator(object):
|
|||||||
return all_names
|
return all_names
|
||||||
|
|
||||||
# TODO: make "sites-available" a configurable directory
|
# TODO: make "sites-available" a configurable directory
|
||||||
def get_virtual_hosts(self):
|
def _get_vhosts(self):
|
||||||
"""Returns list of virtual hosts found in the Nginx configuration.
|
"""Returns list of virtual hosts found in the Nginx configuration.
|
||||||
|
|
||||||
:returns: List of
|
:returns: List of
|
||||||
@@ -261,7 +258,7 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
return vhs
|
return vhs
|
||||||
|
|
||||||
def make_vhost_ssl(self, nonssl_vhost): # pylint: disable=too-many-locals
|
def _make_vhost_ssl(self, nonssl_vhost): # pylint: disable=too-many-locals
|
||||||
"""Makes an ssl_vhost version of a nonssl_vhost.
|
"""Makes an ssl_vhost version of a nonssl_vhost.
|
||||||
|
|
||||||
Duplicates vhost and adds default ssl options
|
Duplicates vhost and adds default ssl options
|
||||||
@@ -296,7 +293,7 @@ class NginxConfigurator(object):
|
|||||||
new_file.write(line)
|
new_file.write(line)
|
||||||
new_file.write("</IfModule>\n")
|
new_file.write("</IfModule>\n")
|
||||||
except IOError:
|
except IOError:
|
||||||
logging.fatal("Error writing/reading to file in make_vhost_ssl")
|
logging.fatal("Error writing/reading to file in _make_vhost_ssl")
|
||||||
sys.exit(49)
|
sys.exit(49)
|
||||||
|
|
||||||
self.aug.load()
|
self.aug.load()
|
||||||
@@ -356,12 +353,13 @@ class NginxConfigurator(object):
|
|||||||
for vhost in self.vhosts:
|
for vhost in self.vhosts:
|
||||||
if vhost.ssl:
|
if vhost.ssl:
|
||||||
# TODO: get the cert, key, and conf file paths
|
# TODO: get the cert, key, and conf file paths
|
||||||
|
pass
|
||||||
|
|
||||||
return c_k
|
return c_k
|
||||||
|
|
||||||
#####################
|
##################################
|
||||||
# enhancement methods
|
# enhancement methods (IInstaller)
|
||||||
#####################
|
##################################
|
||||||
def supported_enhancements(self): # pylint: disable=no-self-use
|
def supported_enhancements(self): # pylint: disable=no-self-use
|
||||||
"""Returns currently supported enhancements."""
|
"""Returns currently supported enhancements."""
|
||||||
return []
|
return []
|
||||||
@@ -386,10 +384,10 @@ class NginxConfigurator(object):
|
|||||||
except errors.LetsEncryptConfiguratorError:
|
except errors.LetsEncryptConfiguratorError:
|
||||||
logging.warn("Failed %s for %s", enhancement, domain)
|
logging.warn("Failed %s for %s", enhancement, domain)
|
||||||
|
|
||||||
#########################
|
######################################
|
||||||
# Nginx server management
|
# Nginx server management (IInstaller)
|
||||||
#########################
|
######################################
|
||||||
def is_site_enabled(self, avail_fp):
|
def _is_site_enabled(self, avail_fp):
|
||||||
"""Checks to see if the given site is enabled.
|
"""Checks to see if the given site is enabled.
|
||||||
|
|
||||||
.. todo:: fix hardcoded sites-enabled, check os.path.samefile
|
.. todo:: fix hardcoded sites-enabled, check os.path.samefile
|
||||||
@@ -407,7 +405,7 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def enable_site(self, vhost):
|
def _enable_site(self, vhost):
|
||||||
"""Enables an available site, Nginx restart required.
|
"""Enables an available site, Nginx restart required.
|
||||||
|
|
||||||
.. todo:: This function should number subdomains before the domain vhost
|
.. todo:: This function should number subdomains before the domain vhost
|
||||||
@@ -421,7 +419,7 @@ class NginxConfigurator(object):
|
|||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.is_site_enabled(vhost.filep):
|
if self._is_site_enabled(vhost.filep):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if "/sites-available/" in vhost.filep:
|
if "/sites-available/" in vhost.filep:
|
||||||
@@ -470,7 +468,7 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def verify_setup(self):
|
def _verify_setup(self):
|
||||||
"""Verify the setup to ensure safe operating environment.
|
"""Verify the setup to ensure safe operating environment.
|
||||||
|
|
||||||
Make sure that files/directories are setup with appropriate permissions
|
Make sure that files/directories are setup with appropriate permissions
|
||||||
@@ -483,7 +481,7 @@ class NginxConfigurator(object):
|
|||||||
le_util.make_or_verify_dir(self.config.work_dir, 0o755, uid)
|
le_util.make_or_verify_dir(self.config.work_dir, 0o755, uid)
|
||||||
le_util.make_or_verify_dir(self.config.backup_dir, 0o755, uid)
|
le_util.make_or_verify_dir(self.config.backup_dir, 0o755, uid)
|
||||||
|
|
||||||
def get_version(self):
|
def _get_version(self):
|
||||||
"""Return version of Nginx Server.
|
"""Return version of Nginx Server.
|
||||||
|
|
||||||
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
|
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
|
||||||
@@ -539,9 +537,9 @@ class NginxConfigurator(object):
|
|||||||
version=".".join(str(i) for i in self.version))
|
version=".".join(str(i) for i in self.version))
|
||||||
)
|
)
|
||||||
|
|
||||||
######################################
|
###################################################
|
||||||
# Wrapper functions for Reverter class
|
# Wrapper functions for Reverter class (IInstaller)
|
||||||
######################################
|
###################################################
|
||||||
def save(self, title=None, temporary=False):
|
def save(self, title=None, temporary=False):
|
||||||
"""Saves all changes to the configuration files.
|
"""Saves all changes to the configuration files.
|
||||||
|
|
||||||
@@ -571,6 +569,7 @@ class NginxConfigurator(object):
|
|||||||
os.rename(f + '.le', f)
|
os.rename(f + '.le', f)
|
||||||
else:
|
else:
|
||||||
logging.warn("Expected file %s to exist", tmpfile)
|
logging.warn("Expected file %s to exist", tmpfile)
|
||||||
|
self.save_files.remove(f)
|
||||||
|
|
||||||
if title and not temporary:
|
if title and not temporary:
|
||||||
self.reverter.finalize_checkpoint(title)
|
self.reverter.finalize_checkpoint(title)
|
||||||
@@ -602,12 +601,13 @@ class NginxConfigurator(object):
|
|||||||
self.reverter.view_config_changes()
|
self.reverter.view_config_changes()
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Challenges Section
|
# Challenges Section for IAuthenticator
|
||||||
###########################################################################
|
###########################################################################
|
||||||
def get_chall_pref(self, unused_domain): # pylint: disable=no-self-use
|
def get_chall_pref(self, unused_domain): # pylint: disable=no-self-use
|
||||||
"""Return list of challenge preferences."""
|
"""Return list of challenge preferences."""
|
||||||
return [challenges.DVSNI]
|
return [challenges.DVSNI]
|
||||||
|
|
||||||
|
# Entry point in main.py for performing challenges
|
||||||
def perform(self, achalls):
|
def perform(self, achalls):
|
||||||
"""Perform the configuration related challenge.
|
"""Perform the configuration related challenge.
|
||||||
|
|
||||||
@@ -640,6 +640,7 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
return responses
|
return responses
|
||||||
|
|
||||||
|
# called after challenges are performed
|
||||||
def cleanup(self, achalls):
|
def cleanup(self, achalls):
|
||||||
"""Revert all challenges."""
|
"""Revert all challenges."""
|
||||||
self._chall_out -= len(achalls)
|
self._chall_out -= len(achalls)
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
"""NginxParser is a member object of the NginxConfigurator class."""
|
"""NginxParser is a member object of the NginxConfigurator class."""
|
||||||
|
import glob
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import pyparsing
|
||||||
|
|
||||||
from letsencrypt.client import errors
|
from letsencrypt.client import errors
|
||||||
|
from letsencrypt.client.plugins.nginx.nginxparser import dump, load
|
||||||
|
|
||||||
|
|
||||||
class NginxParser(object):
|
class NginxParser(object):
|
||||||
@@ -10,22 +14,19 @@ class NginxParser(object):
|
|||||||
|
|
||||||
:ivar str root: Normalized abosulte path to the server root
|
:ivar str root: Normalized abosulte path to the server root
|
||||||
directory. Without trailing slash.
|
directory. Without trailing slash.
|
||||||
|
:ivar dict parsed: Mapping of file paths to parsed trees
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, aug, root, ssl_options):
|
def __init__(self, root, ssl_options):
|
||||||
# Find configuration root and make sure augeas can parse it.
|
self.parsed = {}
|
||||||
self.aug = aug
|
|
||||||
self.root = os.path.abspath(root)
|
self.root = os.path.abspath(root)
|
||||||
self.loc = self._set_locations(ssl_options)
|
self.loc = self._set_locations(ssl_options)
|
||||||
self._parse_file(self.loc["root"])
|
self._parse_file(self.loc["root"])
|
||||||
|
|
||||||
# Must also attempt to parse sites-available or equivalent
|
# Must also attempt to parse sites-available or equivalent
|
||||||
# Sites-available is not included naturally in configuration
|
# Sites-available is not included naturally in configuration
|
||||||
self._parse_file(os.path.join(self.root, "sites-available") + "/*")
|
self._parse_file(os.path.join(self.root, "sites-available") + "/*.conf")
|
||||||
|
|
||||||
# This problem has been fixed in Augeas 1.0
|
|
||||||
self.standardize_excl()
|
|
||||||
|
|
||||||
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
||||||
"""Adds directive and value to IfMod ssl block.
|
"""Adds directive and value to IfMod ssl block.
|
||||||
@@ -246,24 +247,19 @@ class NginxParser(object):
|
|||||||
return regex
|
return regex
|
||||||
|
|
||||||
def _parse_file(self, filepath):
|
def _parse_file(self, filepath):
|
||||||
"""Parse file with Augeas
|
"""Parse file
|
||||||
|
|
||||||
Checks to see if file_path is parsed by Augeas
|
|
||||||
If filepath isn't parsed, the file is added and Augeas is reloaded
|
|
||||||
|
|
||||||
:param str filepath: Nginx config file path
|
:param str filepath: Nginx config file path
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Test if augeas included file for Httpd.lens
|
files = glob.glob(filepath)
|
||||||
# Note: This works for augeas globs, ie. *.conf
|
for f in files:
|
||||||
inc_test = self.aug.match(
|
try:
|
||||||
"/augeas/load/Httpd/incl [. ='%s']" % filepath)
|
self.parsed[f] = load(open(f))
|
||||||
if not inc_test:
|
except IOError:
|
||||||
# Load up files
|
logging.warn("Could not parse file: %s" % f)
|
||||||
# This doesn't seem to work on TravisCI
|
except pyparsing.ParseException:
|
||||||
# self.aug.add_transform("Httpd.lns", [filepath])
|
logging.warn("Could not parse file: %s" % f)
|
||||||
self._add_httpd_transform(filepath)
|
|
||||||
self.aug.load()
|
|
||||||
|
|
||||||
def _add_httpd_transform(self, incl):
|
def _add_httpd_transform(self, incl):
|
||||||
"""Add a transform to Augeas.
|
"""Add a transform to Augeas.
|
||||||
@@ -286,38 +282,6 @@ class NginxParser(object):
|
|||||||
self.aug.set("/augeas/load/Httpd/lens", "Httpd.lns")
|
self.aug.set("/augeas/load/Httpd/lens", "Httpd.lns")
|
||||||
self.aug.set("/augeas/load/Httpd/incl", incl)
|
self.aug.set("/augeas/load/Httpd/incl", incl)
|
||||||
|
|
||||||
def standardize_excl(self):
|
|
||||||
"""Standardize the excl arguments for the Httpd lens in Augeas.
|
|
||||||
|
|
||||||
Note: Hack!
|
|
||||||
Standardize the excl arguments for the Httpd lens in Augeas
|
|
||||||
Servers sometimes give incorrect defaults
|
|
||||||
Note: This problem should be fixed in Augeas 1.0. Unfortunately,
|
|
||||||
Augeas 0.10 appears to be the most popular version currently.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# attempt to protect against augeas error in 0.10.0 - ubuntu
|
|
||||||
# *.augsave -> /*.augsave upon augeas.load()
|
|
||||||
# Try to avoid bad httpd files
|
|
||||||
# There has to be a better way... but after a day and a half of testing
|
|
||||||
# I had no luck
|
|
||||||
# This is a hack... work around... submit to augeas if still not fixed
|
|
||||||
|
|
||||||
excl = ["*.augnew", "*.augsave", "*.dpkg-dist", "*.dpkg-bak",
|
|
||||||
"*.dpkg-new", "*.dpkg-old", "*.rpmsave", "*.rpmnew",
|
|
||||||
"*~",
|
|
||||||
self.root + "/*.augsave",
|
|
||||||
self.root + "/*~",
|
|
||||||
self.root + "/*/*augsave",
|
|
||||||
self.root + "/*/*~",
|
|
||||||
self.root + "/*/*/*.augsave",
|
|
||||||
self.root + "/*/*/*~"]
|
|
||||||
|
|
||||||
for i, excluded in enumerate(excl, 1):
|
|
||||||
self.aug.set("/augeas/load/Httpd/excl[%d]" % i, excluded)
|
|
||||||
|
|
||||||
self.aug.load()
|
|
||||||
|
|
||||||
def _set_locations(self, ssl_options):
|
def _set_locations(self, ssl_options):
|
||||||
"""Set default location for directives.
|
"""Set default location for directives.
|
||||||
|
|
||||||
@@ -326,7 +290,7 @@ class NginxParser(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
root = self._find_config_root()
|
root = self._find_config_root()
|
||||||
default = self._set_user_config_file(root)
|
default = os.path.join(self.root, 'nginx.conf')
|
||||||
|
|
||||||
temp = os.path.join(self.root, "ports.conf")
|
temp = os.path.join(self.root, "ports.conf")
|
||||||
if os.path.isfile(temp):
|
if os.path.isfile(temp):
|
||||||
@@ -341,7 +305,7 @@ class NginxParser(object):
|
|||||||
|
|
||||||
def _find_config_root(self):
|
def _find_config_root(self):
|
||||||
"""Find the Nginx Configuration Root file."""
|
"""Find the Nginx Configuration Root file."""
|
||||||
location = ["nginx2.conf", "httpd.conf"]
|
location = ['nginx.conf']
|
||||||
|
|
||||||
for name in location:
|
for name in location:
|
||||||
if os.path.isfile(os.path.join(self.root, name)):
|
if os.path.isfile(os.path.join(self.root, name)):
|
||||||
@@ -350,24 +314,6 @@ class NginxParser(object):
|
|||||||
raise errors.LetsEncryptNoInstallationError(
|
raise errors.LetsEncryptNoInstallationError(
|
||||||
"Could not find configuration root")
|
"Could not find configuration root")
|
||||||
|
|
||||||
def _set_user_config_file(self, root):
|
|
||||||
"""Set the appropriate user configuration file
|
|
||||||
|
|
||||||
.. todo:: This will have to be updated for other distros versions
|
|
||||||
|
|
||||||
:param str root: pathname which contains the user config
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Basic check to see if httpd.conf exists and
|
|
||||||
# in hierarchy via direct include
|
|
||||||
# httpd.conf was very common as a user file in Nginx 2.2
|
|
||||||
if (os.path.isfile(os.path.join(self.root, 'httpd.conf')) and
|
|
||||||
self.find_dir(
|
|
||||||
case_i("Include"), case_i("httpd.conf"), root)):
|
|
||||||
return os.path.join(self.root, 'httpd.conf')
|
|
||||||
else:
|
|
||||||
return os.path.join(self.root, 'nginx2.conf')
|
|
||||||
|
|
||||||
|
|
||||||
def case_i(string):
|
def case_i(string):
|
||||||
"""Returns case insensitive regex.
|
"""Returns case insensitive regex.
|
||||||
|
|||||||
Reference in New Issue
Block a user