Merge "Getting correct count and attributes from database"

This commit is contained in:
Jenkins 2014-02-19 18:06:21 +00:00 committed by Gerrit Code Review
commit 13faf8b889
5 changed files with 151 additions and 40 deletions

View File

@ -25,29 +25,80 @@ import tuskar.heat.template_tools as template_tools
LOG = logging.getLogger(__name__)
# FIXME(lsmola) mocked params for POC, remove later by real ones
# FIXME(lsmola) this is for debugging purposes only, remove before I3
POC_PARAMS = {'controller': 1, 'compute': 1}
POC_PARAMS_UPDATE = {'controller': 1, 'compute': 2}
def process_stack(params, create=False):
"""Helper function for processing the stack. Given a params dict containing
the Overcloud Roles and initialization parameters create or update the
stack.
def parse_counts(counts):
"""Helper for parsing the OvercloudRoleCount object
:param params: Dictionary of initialization params and overcloud roles for
heat template and initialization of stack/
:type params: dict
Given a list of OvercloudRoleCount objects return a dict of
(image_name, count) in a format used for building a template.
:param counts: List of tuskar.api.controllers.v1.models.OvercloudRoleCount
:type counts: list
:return: Dict of (image_name, count)
:rtype: dict
"""
parsed_counts = {}
for count_obj in counts:
image_name = count_obj.overcloud_role.image_name
count = count_obj.num_nodes
parsed_counts[image_name] = count
return parsed_counts
def filter_template_attributes(allowed_data, attributes):
"""Helper filtering attributes for template
Given a list of allowed data and attributes, filter the attributes
only with keys of allowed data and return filtered data.
:param allowed_data: Dict of allowed attributes for template returned by
validating of template.
:type allowed_data: dict
:param attributes: Dict of attributes sent from user in deploying stack
operation
:type attributes: Dict
:return: Dict of filtered attributes
:rtype: dict
"""
allowed_keys = allowed_data.get("Parameters", {}).keys()
filtered_data = dict([(key, value) for key, value in attributes.items()
if key in allowed_keys])
return filtered_data
def process_stack(attributes, counts, create=False):
"""Helper function for processing the stack.
Given a params dict containing the Overcloud Roles and initialization
parameters create or update the stack.
:param attributes: Dictionary of initialization params and overcloud roles
for heat template and initialization of stack
:type attributes: dict
:param counts: Dictionary of counts of roles to be deployed
:type counts: dict
:param create: A flag to designate if we are creating or updating the stack
:type create: bool
"""
overcloud = template_tools.merge_templates(params)
overcloud = template_tools.merge_templates(parse_counts(counts))
heat_client = HeatClient()
stack_exists = heat_client.exists_stack()
if not heat_client.validate_template(overcloud):
valid, allowed_data = heat_client.validate_template(overcloud)
if not valid:
raise exception.InvalidHeatTemplate()
if stack_exists and create:
@ -56,7 +107,13 @@ def process_stack(params, create=False):
elif not stack_exists and not create:
raise exception.StackNotFound()
res = heat_client.create_stack(overcloud, params)
if create:
operation = heat_client.create_stack
else:
operation = heat_client.update_stack
res = operation(overcloud,
filter_template_attributes(allowed_data, attributes))
if not res:
if create:
@ -93,7 +150,6 @@ class OvercloudsController(rest.RestController):
:raises: tuskar.common.exception.OvercloudExists: if an overcloud
with the given name exists
"""
LOG.debug('Creating overcloud: %s' % transfer_overcloud)
# Persist to the database
@ -110,7 +166,8 @@ class OvercloudsController(rest.RestController):
# step 2- put the right stack_id to the overcloud
# step 3- initialize the stack
# step 4- set the correct overcloud status
process_stack(POC_PARAMS, create=True)
process_stack(saved_overcloud.attributes, result.counts,
create=True)
return saved_overcloud
@ -145,15 +202,16 @@ class OvercloudsController(rest.RestController):
# Will raise a not found if there is no overcloud with the ID
result = pecan.request.dbapi.update_overcloud(db_delta)
updated = models.Overcloud.from_db_model(result)
updated_overcloud = models.Overcloud.from_db_model(result)
# FIXME(lsmola) This is just POC of updating a stack
# this probably should also have workflow
# step one- build template and stack-update
# step 2- set the correct overcloud status
process_stack(POC_PARAMS_UPDATE)
process_stack(updated_overcloud.attributes, updated_overcloud.counts,
create=True)
return updated
return updated_overcloud
@wsme_pecan.wsexpose(None, int, status_code=204)
def delete(self, overcloud_id):
@ -168,6 +226,10 @@ class OvercloudsController(rest.RestController):
# FIXME(lsmola) this should always try to delete both overcloud
# and stack. So it requires some exception catch over below.
# FIXME(lsmola) there is also a workflow needed
# step one- delete stack and set status deleting in progress to
# overcloud
# step 2 - once stack is deleted, delete the overcloud
LOG.debug('Deleting overcloud with ID: %s' % overcloud_id)
pecan.request.dbapi.delete_overcloud_by_id(overcloud_id)

View File

@ -95,11 +95,12 @@ class HeatClient(object):
def validate_template(self, template_body):
"""Validate given Heat template."""
try:
self.connection.stacks.validate(template=template_body)
return True
allowed_data = self.connection.stacks.validate(
template=template_body)
return True, allowed_data
except Exception:
LOG.exception("Validation of the Heat template failed.")
return False
return False, None
def get_stack(self, name=None):
"""Get overcloud Heat template."""

View File

@ -23,7 +23,7 @@ from tripleo_heat_merge import merge
# The name of the compute Overcloud role - defined for special case handling
OVERCLOUD_COMPUTE_ROLE = 'compute'
OVERCLOUD_COMPUTE_ROLE = 'overcloud-compute'
def generate_scaling_params(overcloud_roles):

View File

@ -71,10 +71,55 @@ class OvercloudTests(base.TestCase):
mock_db_get.assert_called_once_with(12345)
def test_parse_counts(self):
# Setup
overcloud_role_1 = db_models.OvercloudRole(
image_name='overcloud-compute')
overcloud_role_2 = db_models.OvercloudRole(
image_name='overcloud-block-storage')
overcloud_role_count_1 = db_models.OvercloudRoleCount(
overcloud_role_id=2, num_nodes=5, overcloud_role=overcloud_role_1)
overcloud_role_count_2 = db_models.OvercloudRoleCount(
overcloud_role_id=2, num_nodes=9, overcloud_role=overcloud_role_2)
mock_counts = [overcloud_role_count_1, overcloud_role_count_2]
# Test
result = overcloud.parse_counts(mock_counts)
# Verify
self.assertEqual(result, {'overcloud-compute': 5,
'overcloud-block-storage': 9})
def test_filter_template_attributes(self):
# Setup
allowed_data = {'Parameters': {
'Allowed_1': 42,
'Allowed_2': 21,
}}
attributes = {
'NotAllowed_1': "Infinity",
'Allowed_1': 42,
'NotAllowed_2': "SubZero",
'Allowed_2': 21,
'NotAllowed_3': "Goro",
}
# Test
result = overcloud.filter_template_attributes(allowed_data, attributes)
# Verify
self.assertEqual(result, {'Allowed_1': 42,
'Allowed_2': 21})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': False,
'create_stack.return_value': True,
})
@ -84,7 +129,7 @@ class OvercloudTests(base.TestCase):
mock_heat_merge_templates.return_value = None
# Test
response = overcloud.process_stack({}, create=True)
response = overcloud.process_stack({}, {}, create=True)
# Verify
self.assertEqual(response, None)
@ -92,7 +137,7 @@ class OvercloudTests(base.TestCase):
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': False,
'create_stack.return_value': False,
})
@ -105,12 +150,12 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatTemplateCreateFailed,
overcloud.process_stack, {}, True)
overcloud.process_stack, {}, {}, True)
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': True,
'create_stack.return_value': True,
})
@ -122,12 +167,13 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.StackAlreadyCreated, overcloud.process_stack, {}, True)
exception.StackAlreadyCreated, overcloud.process_stack, {}, {},
True)
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': False,
'validate_template.return_value': (False, {}),
'exists_stack.return_value': False,
'create_stack.return_value': True,
})
@ -139,7 +185,8 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.InvalidHeatTemplate, overcloud.process_stack, {}, True)
exception.InvalidHeatTemplate, overcloud.process_stack, {}, {},
True)
@mock.patch('tuskar.api.controllers.v1.overcloud.process_stack')
@mock.patch('tuskar.db.sqlalchemy.api.Connection.create_overcloud')
@ -168,7 +215,7 @@ class OvercloudTests(base.TestCase):
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': True,
'create_stack.return_value': True,
})
@ -178,7 +225,7 @@ class OvercloudTests(base.TestCase):
mock_heat_merge_templates.return_value = None
# Test
response = overcloud.process_stack({})
response = overcloud.process_stack({}, {})
# Verify
self.assertEqual(response, None)
@ -186,9 +233,9 @@ class OvercloudTests(base.TestCase):
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': True,
'create_stack.return_value': False,
'update_stack.return_value': False,
})
)
def test_update_stack_heat_exception(self, mock_heat_client,
@ -198,12 +245,13 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatTemplateUpdateFailed, overcloud.process_stack, {})
exception.HeatTemplateUpdateFailed, overcloud.process_stack, {},
{})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': True,
'validate_template.return_value': (True, {}),
'exists_stack.return_value': False,
'create_stack.return_value': True,
})
@ -215,12 +263,12 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.StackNotFound, overcloud.process_stack, {})
exception.StackNotFound, overcloud.process_stack, {}, {})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': False,
'validate_template.return_value': (False, {}),
'exists_stack.return_value': True,
'create_stack.return_value': True,
})
@ -232,7 +280,7 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.InvalidHeatTemplate, overcloud.process_stack, {})
exception.InvalidHeatTemplate, overcloud.process_stack, {}, {})
@mock.patch('tuskar.api.controllers.v1.overcloud.process_stack')
@mock.patch('tuskar.db.sqlalchemy.api.Connection.update_overcloud')

View File

@ -23,7 +23,7 @@ class TemplateToolsTests(unittest.TestCase):
@mock.patch('tripleo_heat_merge.merge.parse_scaling')
def test_generate_scaling_params(self, mock_parse_scaling):
# Setup
overcloud_roles = {'controller': 1, 'compute': 12}
overcloud_roles = {'controller': 1, 'overcloud-compute': 12}
# Test
template_tools.generate_scaling_params(overcloud_roles)
@ -34,7 +34,7 @@ class TemplateToolsTests(unittest.TestCase):
@mock.patch('tripleo_heat_merge.merge.merge')
def test_merge_templates(self, mock_merge):
# Setup
overcloud_roles = {'controller': 1, 'compute': 12}
overcloud_roles = {'controller': 1, 'overcloud-compute': 12}
# Test
template_tools.merge_templates(overcloud_roles)