Merge "Implement neutron pool resource"
This commit is contained in:
commit
f6b6cf8097
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from heat.common import exception
|
||||||
from heat.engine import clients
|
from heat.engine import clients
|
||||||
from heat.engine import scheduler
|
from heat.engine import scheduler
|
||||||
from heat.engine.resources.neutron import neutron
|
from heat.engine.resources.neutron import neutron
|
||||||
@ -44,7 +45,7 @@ class HealthMonitor(neutron.NeutronResource):
|
|||||||
'expected_codes', 'url_path')
|
'expected_codes', 'url_path')
|
||||||
|
|
||||||
attributes_schema = {
|
attributes_schema = {
|
||||||
'admin_state_up': 'the administrative state of this port',
|
'admin_state_up': 'the administrative state of this health monitor',
|
||||||
'delay': 'the minimum time in seconds between regular connections '
|
'delay': 'the minimum time in seconds between regular connections '
|
||||||
'of the member',
|
'of the member',
|
||||||
'expected_codes': 'the list of HTTP status codes expected in '
|
'expected_codes': 'the list of HTTP status codes expected in '
|
||||||
@ -75,8 +76,9 @@ class HealthMonitor(neutron.NeutronResource):
|
|||||||
self.resource_id)['health_monitor']
|
self.resource_id)['health_monitor']
|
||||||
|
|
||||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||||
self.neutron().update_health_monitor(
|
if prop_diff:
|
||||||
self.resource_id, {'health_monitor': prop_diff})
|
self.neutron().update_health_monitor(
|
||||||
|
self.resource_id, {'health_monitor': prop_diff})
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
try:
|
try:
|
||||||
@ -88,10 +90,158 @@ class HealthMonitor(neutron.NeutronResource):
|
|||||||
return scheduler.TaskRunner(self._confirm_delete)()
|
return scheduler.TaskRunner(self._confirm_delete)()
|
||||||
|
|
||||||
|
|
||||||
|
class Pool(neutron.NeutronResource):
|
||||||
|
"""
|
||||||
|
A resource for managing load balancer pools in Neutron.
|
||||||
|
"""
|
||||||
|
|
||||||
|
vip_schema = {
|
||||||
|
'name': {'Type': 'String'},
|
||||||
|
'description': {'Type': 'String'},
|
||||||
|
'address': {'Type': 'String'},
|
||||||
|
'connection_limit': {'Type': 'Integer'},
|
||||||
|
'protocol_port': {'Type': 'Integer', 'Required': True},
|
||||||
|
'admin_state_up': {'Default': True, 'Type': 'Boolean'},
|
||||||
|
}
|
||||||
|
|
||||||
|
properties_schema = {
|
||||||
|
'protocol': {'Type': 'String', 'Required': True,
|
||||||
|
'AllowedValues': ['TCP', 'HTTP', 'HTTPS']},
|
||||||
|
'subnet_id': {'Type': 'String', 'Required': True},
|
||||||
|
'lb_method': {'Type': 'String', 'Required': True,
|
||||||
|
'AllowedValues': ['ROUND_ROBIN', 'LEAST_CONNECTIONS',
|
||||||
|
'SOURCE_IP']},
|
||||||
|
'name': {'Type': 'String'},
|
||||||
|
'description': {'Type': 'String'},
|
||||||
|
'admin_state_up': {'Default': True, 'Type': 'Boolean'},
|
||||||
|
'vip': {'Type': 'Map', 'Schema': vip_schema, 'Required': True},
|
||||||
|
'monitors': {'Type': 'List'},
|
||||||
|
}
|
||||||
|
|
||||||
|
update_allowed_keys = ('Properties',)
|
||||||
|
update_allowed_properties = ('description', 'admin_state_up', 'lb_method',
|
||||||
|
'monitors')
|
||||||
|
|
||||||
|
attributes_schema = {
|
||||||
|
'admin_state_up': 'the administrative state of this pool',
|
||||||
|
'id': 'unique identifier for this pool',
|
||||||
|
'name': 'friendly name of the pool',
|
||||||
|
'protocol': 'protocol to balance',
|
||||||
|
'subnet_id': 'the subnet on which the members of the pool '
|
||||||
|
'will be located',
|
||||||
|
'lb_method': 'the algorithm used to distribute load between the '
|
||||||
|
'members of the pool',
|
||||||
|
'description': 'description of the pool',
|
||||||
|
'tenant_id': 'tenant owning the pool',
|
||||||
|
'vip': 'ip of the pool',
|
||||||
|
}
|
||||||
|
|
||||||
|
def handle_create(self):
|
||||||
|
properties = self.prepare_properties(
|
||||||
|
self.properties,
|
||||||
|
self.physical_resource_name())
|
||||||
|
vip_properties = properties.pop('vip')
|
||||||
|
monitors = properties.pop('monitors', [])
|
||||||
|
client = self.neutron()
|
||||||
|
pool = client.create_pool({'pool': properties})['pool']
|
||||||
|
self.resource_id_set(pool['id'])
|
||||||
|
|
||||||
|
for monitor in monitors:
|
||||||
|
client.associate_health_monitor(
|
||||||
|
pool['id'], {'health_monitor': {'id': monitor}})
|
||||||
|
|
||||||
|
vip_arguments = self.prepare_properties(
|
||||||
|
vip_properties,
|
||||||
|
'%s.vip' % (self.name,))
|
||||||
|
vip_arguments['protocol'] = self.properties['protocol']
|
||||||
|
vip_arguments['subnet_id'] = self.properties['subnet_id']
|
||||||
|
vip_arguments['pool_id'] = pool['id']
|
||||||
|
vip = client.create_vip({'vip': vip_arguments})['vip']
|
||||||
|
|
||||||
|
self.metadata = {'vip': vip['id']}
|
||||||
|
|
||||||
|
def _show_resource(self):
|
||||||
|
return self.neutron().show_pool(self.resource_id)['pool']
|
||||||
|
|
||||||
|
def check_create_complete(self, data):
|
||||||
|
attributes = self._show_resource()
|
||||||
|
if attributes['status'] == 'PENDING_CREATE':
|
||||||
|
return False
|
||||||
|
elif attributes['status'] == 'ACTIVE':
|
||||||
|
vip_attributes = self.neutron().show_vip(
|
||||||
|
self.metadata['vip'])['vip']
|
||||||
|
if vip_attributes['status'] == 'PENDING_CREATE':
|
||||||
|
return False
|
||||||
|
elif vip_attributes['status'] == 'ACTIVE':
|
||||||
|
return True
|
||||||
|
raise exception.Error(
|
||||||
|
'neutron reported unexpected vip resource[%s] status[%s]' %
|
||||||
|
(vip_attributes['name'], vip_attributes['status']))
|
||||||
|
raise exception.Error(
|
||||||
|
'neutron report unexpected pool resource[%s] status[%s]' %
|
||||||
|
(attributes['name'], attributes['status']))
|
||||||
|
|
||||||
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||||
|
if prop_diff:
|
||||||
|
client = self.neutron()
|
||||||
|
monitors = set(prop_diff.pop('monitors', []))
|
||||||
|
if monitors:
|
||||||
|
old_monitors = set(self.t['Properties'].get('monitors', []))
|
||||||
|
for monitor in old_monitors - monitors:
|
||||||
|
client.disassociate_health_monitor(
|
||||||
|
self.resource_id, {'health_monitor': {'id': monitor}})
|
||||||
|
for monitor in monitors - old_monitors:
|
||||||
|
client.associate_health_monitor(
|
||||||
|
self.resource_id, {'health_monitor': {'id': monitor}})
|
||||||
|
|
||||||
|
if prop_diff:
|
||||||
|
client.update_pool(self.resource_id, {'pool': prop_diff})
|
||||||
|
|
||||||
|
def _resolve_attribute(self, name):
|
||||||
|
if name == 'vip':
|
||||||
|
return self.neutron().show_vip(self.metadata['vip'])['vip']
|
||||||
|
return super(Pool, self)._resolve_attribute(name)
|
||||||
|
|
||||||
|
def _confirm_vip_delete(self):
|
||||||
|
client = self.neutron()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
client.show_vip(self.metadata['vip'])
|
||||||
|
except NeutronClientException as ex:
|
||||||
|
if ex.status_code != 404:
|
||||||
|
raise ex
|
||||||
|
break
|
||||||
|
self._delete_pool()
|
||||||
|
|
||||||
|
def _delete_pool(self):
|
||||||
|
try:
|
||||||
|
self.neutron().delete_pool(self.resource_id)
|
||||||
|
except NeutronClientException as ex:
|
||||||
|
if ex.status_code != 404:
|
||||||
|
raise ex
|
||||||
|
else:
|
||||||
|
return scheduler.TaskRunner(self._confirm_delete)()
|
||||||
|
|
||||||
|
def handle_delete(self):
|
||||||
|
if self.metadata:
|
||||||
|
try:
|
||||||
|
self.neutron().delete_vip(self.metadata['vip'])
|
||||||
|
except NeutronClientException as ex:
|
||||||
|
if ex.status_code != 404:
|
||||||
|
raise ex
|
||||||
|
self._delete_pool()
|
||||||
|
else:
|
||||||
|
return scheduler.TaskRunner(self._confirm_vip_delete)()
|
||||||
|
else:
|
||||||
|
self._delete_pool()
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
if clients.neutronclient is None:
|
if clients.neutronclient is None:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'OS::Neutron::HealthMonitor': HealthMonitor,
|
'OS::Neutron::HealthMonitor': HealthMonitor,
|
||||||
|
'OS::Neutron::Pool': Pool,
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,27 @@ health_monitor_template = '''
|
|||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
pool_template = '''
|
||||||
|
{
|
||||||
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
|
"Description" : "Template to test load balancer resources",
|
||||||
|
"Parameters" : {},
|
||||||
|
"Resources" : {
|
||||||
|
"pool": {
|
||||||
|
"Type": "OS::Neutron::Pool",
|
||||||
|
"Properties": {
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"subnet_id": "sub123",
|
||||||
|
"lb_method": "ROUND_ROBIN",
|
||||||
|
"vip": {
|
||||||
|
"protocol_port": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@skipIf(neutronclient is None, 'neutronclient unavailable')
|
@skipIf(neutronclient is None, 'neutronclient unavailable')
|
||||||
class HealthMonitorTest(HeatTestCase):
|
class HealthMonitorTest(HeatTestCase):
|
||||||
@ -95,13 +116,16 @@ class HealthMonitorTest(HeatTestCase):
|
|||||||
stack = utils.parse_stack(snippet)
|
stack = utils.parse_stack(snippet)
|
||||||
rsrc = loadbalancer.HealthMonitor(
|
rsrc = loadbalancer.HealthMonitor(
|
||||||
'monitor', snippet['Resources']['monitor'], stack)
|
'monitor', snippet['Resources']['monitor'], stack)
|
||||||
self.assertRaises(exception.ResourceFailure,
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
scheduler.TaskRunner(rsrc.create))
|
scheduler.TaskRunner(rsrc.create))
|
||||||
|
self.assertEqual(
|
||||||
|
'NeutronClientException: An unknown exception occurred.',
|
||||||
|
str(error))
|
||||||
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
|
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
neutronclient.Client.delete_health_monitor('5678').AndReturn(None)
|
neutronclient.Client.delete_health_monitor('5678')
|
||||||
neutronclient.Client.show_health_monitor('5678').AndRaise(
|
neutronclient.Client.show_health_monitor('5678').AndRaise(
|
||||||
loadbalancer.NeutronClientException(status_code=404))
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
|
||||||
@ -130,8 +154,11 @@ class HealthMonitorTest(HeatTestCase):
|
|||||||
rsrc = self.create_health_monitor()
|
rsrc = self.create_health_monitor()
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
self.assertRaises(exception.ResourceFailure,
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
scheduler.TaskRunner(rsrc.delete))
|
scheduler.TaskRunner(rsrc.delete))
|
||||||
|
self.assertEqual(
|
||||||
|
'NeutronClientException: An unknown exception occurred.',
|
||||||
|
str(error))
|
||||||
self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
|
self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
@ -150,14 +177,17 @@ class HealthMonitorTest(HeatTestCase):
|
|||||||
rsrc = self.create_health_monitor()
|
rsrc = self.create_health_monitor()
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
self.assertRaises(exception.InvalidTemplateAttribute,
|
error = self.assertRaises(exception.InvalidTemplateAttribute,
|
||||||
rsrc.FnGetAtt, 'subnet_id')
|
rsrc.FnGetAtt, 'subnet_id')
|
||||||
|
self.assertEqual(
|
||||||
|
'The Referenced Attribute (monitor subnet_id) is incorrect.',
|
||||||
|
str(error))
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
rsrc = self.create_health_monitor()
|
rsrc = self.create_health_monitor()
|
||||||
neutronclient.Client.update_health_monitor(
|
neutronclient.Client.update_health_monitor(
|
||||||
'5678', {'health_monitor': {'delay': 10}}).AndReturn(None)
|
'5678', {'health_monitor': {'delay': 10}})
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
@ -166,3 +196,324 @@ class HealthMonitorTest(HeatTestCase):
|
|||||||
self.assertEqual(None, rsrc.update(update_template))
|
self.assertEqual(None, rsrc.update(update_template))
|
||||||
|
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(neutronclient is None, 'neutronclient unavailable')
|
||||||
|
class PoolTest(HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(PoolTest, self).setUp()
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'create_pool')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'delete_pool')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'show_pool')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'update_pool')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client,
|
||||||
|
'associate_health_monitor')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client,
|
||||||
|
'disassociate_health_monitor')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'create_vip')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'delete_vip')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client, 'show_vip')
|
||||||
|
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
|
||||||
|
utils.setup_dummy_db()
|
||||||
|
|
||||||
|
def create_pool(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndReturn({'pool': {'id': '5678'}})
|
||||||
|
neutronclient.Client.create_vip({
|
||||||
|
'vip': {
|
||||||
|
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||||
|
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||||
|
'pool_id': '5678', 'protocol_port': 80}}
|
||||||
|
).AndReturn({'vip': {'id': 'xyz'}})
|
||||||
|
neutronclient.Client.show_pool('5678').AndReturn(
|
||||||
|
{'pool': {'status': 'ACTIVE'}})
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'status': 'ACTIVE'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
return loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_create_pending(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndReturn({'pool': {'id': '5678'}})
|
||||||
|
neutronclient.Client.create_vip({
|
||||||
|
'vip': {
|
||||||
|
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||||
|
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||||
|
'pool_id': '5678', 'protocol_port': 80}}
|
||||||
|
).AndReturn({'vip': {'id': 'xyz'}})
|
||||||
|
neutronclient.Client.show_pool('5678').AndReturn(
|
||||||
|
{'pool': {'status': 'PENDING_CREATE'}})
|
||||||
|
neutronclient.Client.show_pool('5678').MultipleTimes().AndReturn(
|
||||||
|
{'pool': {'status': 'ACTIVE'}})
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'status': 'PENDING_CREATE'}})
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'status': 'ACTIVE'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
rsrc = loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_create_failed_unexpected_status(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndReturn({'pool': {'id': '5678'}})
|
||||||
|
neutronclient.Client.create_vip({
|
||||||
|
'vip': {
|
||||||
|
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||||
|
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||||
|
'pool_id': '5678', 'protocol_port': 80}}
|
||||||
|
).AndReturn({'vip': {'id': 'xyz'}})
|
||||||
|
neutronclient.Client.show_pool('5678').AndReturn(
|
||||||
|
{'pool': {'status': 'ERROR', 'name': '5678'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
rsrc = loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
self.m.ReplayAll()
|
||||||
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(rsrc.create))
|
||||||
|
self.assertEqual(
|
||||||
|
'Error: neutron report unexpected pool '
|
||||||
|
'resource[5678] status[ERROR]',
|
||||||
|
str(error))
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_create_failed_unexpected_vip_status(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndReturn({'pool': {'id': '5678'}})
|
||||||
|
neutronclient.Client.create_vip({
|
||||||
|
'vip': {
|
||||||
|
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||||
|
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||||
|
'pool_id': '5678', 'protocol_port': 80}}
|
||||||
|
).AndReturn({'vip': {'id': 'xyz'}})
|
||||||
|
neutronclient.Client.show_pool('5678').MultipleTimes().AndReturn(
|
||||||
|
{'pool': {'status': 'ACTIVE'}})
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'status': 'ERROR', 'name': 'xyz'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
rsrc = loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
self.m.ReplayAll()
|
||||||
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(rsrc.create))
|
||||||
|
self.assertEqual(
|
||||||
|
'Error: neutron reported unexpected vip '
|
||||||
|
'resource[xyz] status[ERROR]',
|
||||||
|
str(error))
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_create_failed(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndRaise(loadbalancer.NeutronClientException())
|
||||||
|
self.m.ReplayAll()
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
rsrc = loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(rsrc.create))
|
||||||
|
self.assertEqual(
|
||||||
|
'NeutronClientException: An unknown exception occurred.',
|
||||||
|
str(error))
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
neutronclient.Client.delete_vip('xyz')
|
||||||
|
neutronclient.Client.show_vip('xyz').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
neutronclient.Client.delete_pool('5678')
|
||||||
|
neutronclient.Client.show_pool('5678').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_already_gone(self):
|
||||||
|
neutronclient.Client.delete_vip('xyz').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
neutronclient.Client.delete_pool('5678').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_vip_failed(self):
|
||||||
|
neutronclient.Client.delete_vip('xyz').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=400))
|
||||||
|
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(rsrc.delete))
|
||||||
|
self.assertEqual(
|
||||||
|
'NeutronClientException: An unknown exception occurred.',
|
||||||
|
str(error))
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_failed(self):
|
||||||
|
neutronclient.Client.delete_vip('xyz').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=404))
|
||||||
|
neutronclient.Client.delete_pool('5678').AndRaise(
|
||||||
|
loadbalancer.NeutronClientException(status_code=400))
|
||||||
|
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
error = self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(rsrc.delete))
|
||||||
|
self.assertEqual(
|
||||||
|
'NeutronClientException: An unknown exception occurred.',
|
||||||
|
str(error))
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_attribute(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
neutronclient.Client.show_pool('5678').MultipleTimes(
|
||||||
|
).AndReturn(
|
||||||
|
{'pool': {'admin_state_up': True, 'lb_method': 'ROUND_ROBIN'}})
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual(True, rsrc.FnGetAtt('admin_state_up'))
|
||||||
|
self.assertEqual('ROUND_ROBIN', rsrc.FnGetAtt('lb_method'))
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_vip_attribute(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'address': '10.0.0.3', 'name': 'xyz'}})
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual({'address': '10.0.0.3', 'name': 'xyz'},
|
||||||
|
rsrc.FnGetAtt('vip'))
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_attribute_failed(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
error = self.assertRaises(exception.InvalidTemplateAttribute,
|
||||||
|
rsrc.FnGetAtt, 'net_id')
|
||||||
|
self.assertEqual(
|
||||||
|
'The Referenced Attribute (pool net_id) is incorrect.',
|
||||||
|
str(error))
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
rsrc = self.create_pool()
|
||||||
|
neutronclient.Client.update_pool(
|
||||||
|
'5678', {'pool': {'admin_state_up': False}})
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
update_template = copy.deepcopy(rsrc.t)
|
||||||
|
update_template['Properties']['admin_state_up'] = False
|
||||||
|
self.assertEqual(None, rsrc.update(update_template))
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_update_monitors(self):
|
||||||
|
clients.OpenStackClients.keystone().AndReturn(
|
||||||
|
fakes.FakeKeystoneClient())
|
||||||
|
neutronclient.Client.create_pool({
|
||||||
|
'pool': {
|
||||||
|
'subnet_id': 'sub123', 'protocol': u'HTTP',
|
||||||
|
'name': utils.PhysName('test_stack', 'pool'),
|
||||||
|
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||||
|
).AndReturn({'pool': {'id': '5678'}})
|
||||||
|
neutronclient.Client.associate_health_monitor(
|
||||||
|
'5678', {'health_monitor': {'id': 'mon123'}})
|
||||||
|
neutronclient.Client.associate_health_monitor(
|
||||||
|
'5678', {'health_monitor': {'id': 'mon456'}})
|
||||||
|
neutronclient.Client.create_vip({
|
||||||
|
'vip': {
|
||||||
|
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||||
|
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||||
|
'pool_id': '5678', 'protocol_port': 80}}
|
||||||
|
).AndReturn({'vip': {'id': 'xyz'}})
|
||||||
|
neutronclient.Client.show_pool('5678').AndReturn(
|
||||||
|
{'pool': {'status': 'ACTIVE'}})
|
||||||
|
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||||
|
{'vip': {'status': 'ACTIVE'}})
|
||||||
|
neutronclient.Client.disassociate_health_monitor(
|
||||||
|
'5678', {'health_monitor': {'id': 'mon456'}})
|
||||||
|
neutronclient.Client.associate_health_monitor(
|
||||||
|
'5678', {'health_monitor': {'id': 'mon789'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(pool_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
snippet['Resources']['pool']['Properties']['monitors'] = [
|
||||||
|
'mon123', 'mon456']
|
||||||
|
rsrc = loadbalancer.Pool(
|
||||||
|
'pool', snippet['Resources']['pool'], stack)
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
update_template = copy.deepcopy(rsrc.t)
|
||||||
|
update_template['Properties']['monitors'] = ['mon123', 'mon789']
|
||||||
|
self.assertEqual(None, rsrc.update(update_template))
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
Loading…
Reference in New Issue
Block a user