Merge "Add support for the httpsRedirect property"
This commit is contained in:
commit
484feb9814
@ -26,6 +26,7 @@ from heat.engine import function
|
||||
from heat.engine import properties
|
||||
from heat.engine import resource
|
||||
from heat.engine import scheduler
|
||||
from heat.engine import support
|
||||
|
||||
try:
|
||||
from pyrax.exceptions import NotFound # noqa
|
||||
@ -78,14 +79,17 @@ class CloudLoadBalancer(resource.Resource):
|
||||
CONNECTION_LOGGING, METADATA, PORT, TIMEOUT,
|
||||
CONNECTION_THROTTLE, SESSION_PERSISTENCE, VIRTUAL_IPS,
|
||||
CONTENT_CACHING, HEALTH_MONITOR, SSL_TERMINATION, ERROR_PAGE,
|
||||
HTTPS_REDIRECT,
|
||||
) = (
|
||||
'name', 'nodes', 'protocol', 'accessList', 'halfClosed', 'algorithm',
|
||||
'connectionLogging', 'metadata', 'port', 'timeout',
|
||||
'connectionThrottle', 'sessionPersistence', 'virtualIps',
|
||||
'contentCaching', 'healthMonitor', 'sslTermination', 'errorPage',
|
||||
'httpsRedirect',
|
||||
)
|
||||
|
||||
LB_UPDATE_PROPS = (NAME, ALGORITHM, PROTOCOL, HALF_CLOSED, PORT, TIMEOUT)
|
||||
LB_UPDATE_PROPS = (NAME, ALGORITHM, PROTOCOL, HALF_CLOSED, PORT, TIMEOUT,
|
||||
HTTPS_REDIRECT)
|
||||
|
||||
_NODE_KEYS = (
|
||||
NODE_ADDRESSES, NODE_PORT, NODE_CONDITION, NODE_TYPE,
|
||||
@ -428,6 +432,19 @@ class CloudLoadBalancer(resource.Resource):
|
||||
properties.Schema.STRING,
|
||||
update_allowed=True
|
||||
),
|
||||
HTTPS_REDIRECT: properties.Schema(
|
||||
properties.Schema.BOOLEAN,
|
||||
_("Enables or disables HTTP to HTTPS redirection for the load "
|
||||
"balancer. When enabled, any HTTP request returns status code "
|
||||
"301 (Moved Permanently), and the requester is redirected to "
|
||||
"the requested URL via the HTTPS protocol on port 443. Only "
|
||||
"available for HTTPS protocol (port=443), or HTTP protocol with "
|
||||
"a properly configured SSL termination (secureTrafficOnly=true, "
|
||||
"securePort=443)."),
|
||||
update_allowed=True,
|
||||
default=False,
|
||||
support_status=support.SupportStatus(version="2015.1")
|
||||
)
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
@ -557,6 +574,7 @@ class CloudLoadBalancer(resource.Resource):
|
||||
'sessionPersistence': session_persistence,
|
||||
'timeout': self.properties.get(self.TIMEOUT),
|
||||
'connectionLogging': connection_logging,
|
||||
self.HTTPS_REDIRECT: self.properties[self.HTTPS_REDIRECT]
|
||||
}
|
||||
|
||||
lb_name = (self.properties.get(self.NAME) or
|
||||
@ -886,6 +904,22 @@ class CloudLoadBalancer(resource.Resource):
|
||||
function.resolve,
|
||||
self.name).validate()
|
||||
|
||||
# validate if HTTPS_REDIRECT is true and we're not HTTPS
|
||||
redir = self.properties[self.HTTPS_REDIRECT]
|
||||
proto = self.properties[self.PROTOCOL]
|
||||
|
||||
if redir and (proto != "HTTPS"):
|
||||
termcfg = self.properties.get(self.SSL_TERMINATION) or {}
|
||||
seconly = termcfg.get(self.SSL_TERMINATION_SECURE_TRAFFIC_ONLY,
|
||||
False)
|
||||
secport = termcfg.get(self.SSL_TERMINATION_SECURE_PORT, 0)
|
||||
if not (seconly and (secport == 443) and (proto == "HTTP")):
|
||||
message = _("HTTPS redirect is only available for the HTTPS "
|
||||
"protocol (port=443), or the HTTP protocol with "
|
||||
"a properly configured SSL termination "
|
||||
"(secureTrafficOnly=true, securePort=443).")
|
||||
raise exception.StackValidationFailed(message=message)
|
||||
|
||||
# if a vip specifies and id, it can't specify version or type;
|
||||
# otherwise version and type are required
|
||||
for vip in self.properties.get(self.VIRTUAL_IPS, []):
|
||||
|
@ -325,7 +325,9 @@ class LoadBalancerTest(common.HeatTestCase):
|
||||
"healthMonitor": None,
|
||||
"metadata": None,
|
||||
"sessionPersistence": None,
|
||||
"timeout": 110
|
||||
"timeout": 110,
|
||||
"httpsRedirect": False
|
||||
|
||||
}
|
||||
|
||||
lb.resource_mapping = override_resource
|
||||
@ -910,6 +912,30 @@ class LoadBalancerTest(common.HeatTestCase):
|
||||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_update_lb_redirect(self):
|
||||
templ = copy.deepcopy(self.lb_template)
|
||||
rsrs = templ['Resources'].values()[0]
|
||||
rsrs['Properties']['protocol'] = "HTTPS"
|
||||
rsrc, fake_loadbalancer = self._mock_loadbalancer(self.lb_template,
|
||||
self.lb_name,
|
||||
self.expected_body)
|
||||
self.m.ReplayAll()
|
||||
scheduler.TaskRunner(rsrc.create)()
|
||||
|
||||
update_template = copy.deepcopy(rsrc.t)
|
||||
update_template['Properties']['httpsRedirect'] = True
|
||||
|
||||
self.m.StubOutWithMock(rsrc.clb, 'get')
|
||||
rsrc.clb.get(rsrc.resource_id).AndReturn(fake_loadbalancer)
|
||||
|
||||
self.m.StubOutWithMock(fake_loadbalancer, 'update')
|
||||
fake_loadbalancer.update(httpsRedirect=True)
|
||||
|
||||
self.m.ReplayAll()
|
||||
scheduler.TaskRunner(rsrc.update, update_template)()
|
||||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_update_lb_half_closed(self):
|
||||
rsrc, fake_loadbalancer = self._mock_loadbalancer(self.lb_template,
|
||||
self.lb_name,
|
||||
@ -1497,3 +1523,81 @@ class LoadBalancerTest(common.HeatTestCase):
|
||||
|
||||
res = mock_loadbalancer.check_delete_complete(mock_task)
|
||||
self.assertTrue(res)
|
||||
|
||||
def test_redir(self):
|
||||
mock_stack = mock.Mock()
|
||||
mock_stack.db_resource_get.return_value = None
|
||||
props = {'httpsRedirect': True,
|
||||
'protocol': 'HTTPS',
|
||||
'port': 443,
|
||||
'nodes': [],
|
||||
'virtualIps': [{'id': '1234'}]}
|
||||
mock_resdef = rsrc_defn.ResourceDefinition("test_lb",
|
||||
LoadBalancerWithFakeClient,
|
||||
properties=props)
|
||||
mock_lb = lb.CloudLoadBalancer("test", mock_resdef, mock_stack)
|
||||
self.assertIsNone(mock_lb.validate())
|
||||
props['protocol'] = 'HTTP'
|
||||
props['sslTermination'] = {
|
||||
'secureTrafficOnly': True,
|
||||
'securePort': 443,
|
||||
'privatekey': "bobloblaw",
|
||||
'certificate': 'mycert'
|
||||
}
|
||||
mock_resdef = rsrc_defn.ResourceDefinition("test_lb_2",
|
||||
LoadBalancerWithFakeClient,
|
||||
properties=props)
|
||||
mock_lb = lb.CloudLoadBalancer("test_2", mock_resdef, mock_stack)
|
||||
self.assertIsNone(mock_lb.validate())
|
||||
|
||||
def test_invalid_redir_proto(self):
|
||||
mock_stack = mock.Mock()
|
||||
mock_stack.db_resource_get.return_value = None
|
||||
props = {'httpsRedirect': True,
|
||||
'protocol': 'TCP',
|
||||
'port': 1234,
|
||||
'nodes': [],
|
||||
'virtualIps': [{'id': '1234'}]}
|
||||
mock_resdef = rsrc_defn.ResourceDefinition("test_lb",
|
||||
LoadBalancerWithFakeClient,
|
||||
properties=props)
|
||||
mock_lb = lb.CloudLoadBalancer("test", mock_resdef, mock_stack)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
mock_lb.validate)
|
||||
self.assertIn("HTTPS redirect is only available", six.text_type(ex))
|
||||
|
||||
def test_invalid_redir_ssl(self):
|
||||
mock_stack = mock.Mock()
|
||||
mock_stack.db_resource_get.return_value = None
|
||||
props = {'httpsRedirect': True,
|
||||
'protocol': 'HTTP',
|
||||
'port': 1234,
|
||||
'nodes': [],
|
||||
'virtualIps': [{'id': '1234'}]}
|
||||
mock_resdef = rsrc_defn.ResourceDefinition("test_lb",
|
||||
LoadBalancerWithFakeClient,
|
||||
properties=props)
|
||||
mock_lb = lb.CloudLoadBalancer("test", mock_resdef, mock_stack)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
mock_lb.validate)
|
||||
self.assertIn("HTTPS redirect is only available", six.text_type(ex))
|
||||
props['sslTermination'] = {
|
||||
'secureTrafficOnly': False,
|
||||
'securePort': 443,
|
||||
'privatekey': "bobloblaw",
|
||||
'certificate': 'mycert'
|
||||
}
|
||||
mock_lb = lb.CloudLoadBalancer("test", mock_resdef, mock_stack)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
mock_lb.validate)
|
||||
self.assertIn("HTTPS redirect is only available", six.text_type(ex))
|
||||
props['sslTermination'] = {
|
||||
'secureTrafficOnly': True,
|
||||
'securePort': 1234,
|
||||
'privatekey': "bobloblaw",
|
||||
'certificate': 'mycert'
|
||||
}
|
||||
mock_lb = lb.CloudLoadBalancer("test", mock_resdef, mock_stack)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
mock_lb.validate)
|
||||
self.assertIn("HTTPS redirect is only available", six.text_type(ex))
|
||||
|
Loading…
Reference in New Issue
Block a user