Automatically select among default vhosts if we have a port preference in nginx (#5944)

* automatically select among default vhosts if we have a port preference

* ports should be strings in the nginx plugin

* clarify port vs preferred_port behavior by adding allow_port_mismatch flag

* update all instances of default_vhosts to all_default_vhosts

* require port

* port should never be None in _get_default_vhost
This commit is contained in:
ohemorange
2018-06-05 13:40:48 -07:00
committed by Brad Warren
parent 09a28c7a27
commit d905886f4c
2 changed files with 27 additions and 11 deletions
+19 -10
View File
@@ -289,7 +289,8 @@ class NginxConfigurator(common.Installer):
if not vhosts: if not vhosts:
if create_if_no_match: if create_if_no_match:
# result will not be [None] because it errors on failure # result will not be [None] because it errors on failure
vhosts = [self._vhost_from_duplicated_default(target_name)] vhosts = [self._vhost_from_duplicated_default(target_name, True,
str(self.config.tls_sni_01_port))]
else: else:
# No matches. Raise a misconfiguration error. # No matches. Raise a misconfiguration error.
raise errors.MisconfigurationError( raise errors.MisconfigurationError(
@@ -332,9 +333,12 @@ class NginxConfigurator(common.Installer):
ipv6only_present = True ipv6only_present = True
return (ipv6_active, ipv6only_present) return (ipv6_active, ipv6only_present)
def _vhost_from_duplicated_default(self, domain, port=None): def _vhost_from_duplicated_default(self, domain, allow_port_mismatch, port):
"""if allow_port_mismatch is False, only server blocks with matching ports will be
used as a default server block template.
"""
if self.new_vhost is None: if self.new_vhost is None:
default_vhost = self._get_default_vhost(port, domain) default_vhost = self._get_default_vhost(domain, allow_port_mismatch, port)
self.new_vhost = self.parser.duplicate_vhost(default_vhost, self.new_vhost = self.parser.duplicate_vhost(default_vhost,
remove_singleton_listen_params=True) remove_singleton_listen_params=True)
self.new_vhost.names = set() self.new_vhost.names = set()
@@ -350,19 +354,24 @@ class NginxConfigurator(common.Installer):
name_block[0].append(name) name_block[0].append(name)
self.parser.update_or_add_server_directives(vhost, name_block) self.parser.update_or_add_server_directives(vhost, name_block)
def _get_default_vhost(self, port, domain): def _get_default_vhost(self, domain, allow_port_mismatch, port):
"""Helper method for _vhost_from_duplicated_default; see argument documentation there"""
vhost_list = self.parser.get_vhosts() vhost_list = self.parser.get_vhosts()
# if one has default_server set, return that one # if one has default_server set, return that one
default_vhosts = [] all_default_vhosts = []
port_matching_vhosts = []
for vhost in vhost_list: for vhost in vhost_list:
for addr in vhost.addrs: for addr in vhost.addrs:
if addr.default: if addr.default:
if port is None or self._port_matches(port, addr.get_port()): all_default_vhosts.append(vhost)
default_vhosts.append(vhost) if self._port_matches(port, addr.get_port()):
port_matching_vhosts.append(vhost)
break break
if len(default_vhosts) == 1: if len(port_matching_vhosts) == 1:
return default_vhosts[0] return port_matching_vhosts[0]
elif len(all_default_vhosts) == 1 and allow_port_mismatch:
return all_default_vhosts[0]
# TODO: present a list of vhosts for user to choose from # TODO: present a list of vhosts for user to choose from
@@ -471,7 +480,7 @@ class NginxConfigurator(common.Installer):
matches = self._get_redirect_ranked_matches(target_name, port) matches = self._get_redirect_ranked_matches(target_name, port)
vhosts = [x for x in [self._select_best_name_match(matches)]if x is not None] vhosts = [x for x in [self._select_best_name_match(matches)]if x is not None]
if not vhosts and create_if_no_match: if not vhosts and create_if_no_match:
vhosts = [self._vhost_from_duplicated_default(target_name, port=port)] vhosts = [self._vhost_from_duplicated_default(target_name, False, port)]
return vhosts return vhosts
def _port_matches(self, test_port, matching_port): def _port_matches(self, test_port, matching_port):
@@ -731,6 +731,13 @@ class NginxConfiguratorTest(util.NginxTest):
"www.nomatch.com", "example/cert.pem", "example/key.pem", "www.nomatch.com", "example/cert.pem", "example/key.pem",
"example/chain.pem", "example/fullchain.pem") "example/chain.pem", "example/fullchain.pem")
def test_deploy_no_match_multiple_defaults_ok(self):
foo_conf = self.config.parser.abs_path('foo.conf')
self.config.parser.parsed[foo_conf][2][1][0][1][0][1] = '*:5001'
self.config.version = (1, 3, 1)
self.config.deploy_cert("www.nomatch.com", "example/cert.pem", "example/key.pem",
"example/chain.pem", "example/fullchain.pem")
def test_deploy_no_match_add_redirect(self): def test_deploy_no_match_add_redirect(self):
default_conf = self.config.parser.abs_path('sites-enabled/default') default_conf = self.config.parser.abs_path('sites-enabled/default')
foo_conf = self.config.parser.abs_path('foo.conf') foo_conf = self.config.parser.abs_path('foo.conf')