Create stack in right order

-we need to first create Stack, if that doesn't throw exception,
 we create Overcloud. This is a sanity fix, since we are not
 implementing the workflows in I.
-correct stack_id is being passed to Overcloud, before it was
 just blank

Change-Id: If7364e5b35b7343a8b5d0f0278d79f500239ca40
This commit is contained in:
Ladislav Smola 2014-02-25 12:16:48 -05:00 committed by Jiri Stransky
parent aa0e4ea3c7
commit 9f75bc9c70
2 changed files with 67 additions and 38 deletions

View File

@ -30,7 +30,7 @@ LOG = logging.getLogger(__name__)
POC_PARAMS = {'controller': 1, 'compute': 2}
def parse_counts(counts):
def parse_counts(counts, overcloud_roles):
"""Helper for parsing the OvercloudRoleCount object
Given a list of OvercloudRoleCount objects return a dict of
@ -39,12 +39,16 @@ def parse_counts(counts):
:param counts: List of tuskar.api.controllers.v1.models.OvercloudRoleCount
:type counts: list
:param overcloud_roles: Dict of (overcloud_role_id, overcloud_role) so
we can access image_name and flavor_id of roles
:type overcloud_roles: dict
:return: Dict of (image_name, count)
:rtype: dict
"""
parsed_counts = {}
for count_obj in counts:
image_name = count_obj.overcloud_role.image_name
image_name = overcloud_roles[count_obj.overcloud_role_id].image_name
count = count_obj.num_nodes
parsed_counts[image_name] = count
@ -76,7 +80,13 @@ def filter_template_attributes(allowed_data, attributes):
return filtered_data
def process_stack(attributes, counts, create=False):
def get_overcloud_roles_dict():
return dict((overcloud_role.id, overcloud_role)
for overcloud_role in
pecan.request.dbapi.get_overcloud_roles())
def process_stack(attributes, counts, overcloud_roles, create=False):
"""Helper function for processing the stack.
Given a params dict containing the Overcloud Roles and initialization
@ -89,11 +99,16 @@ def process_stack(attributes, counts, create=False):
:param counts: Dictionary of counts of roles to be deployed
:type counts: dict
:param overcloud_roles: Dict of (overcloud_role_id, overcloud_role) so
we can access image_name and flavor_id of roles
:type overcloud_roles: dict
:param create: A flag to designate if we are creating or updating the stack
:type create: bool
"""
try:
overcloud = template_tools.merge_templates(parse_counts(counts))
overcloud = template_tools.merge_templates(
parse_counts(counts, overcloud_roles))
except Exception as e:
raise exception.HeatTemplateCreateFailed(six.text_type(e))
@ -117,14 +132,17 @@ def process_stack(attributes, counts, create=False):
operation = heat_client.update_stack
try:
operation(overcloud,
filter_template_attributes(allowed_data, attributes))
result = operation(
overcloud,
filter_template_attributes(allowed_data, attributes))
except Exception as e:
if create:
raise exception.HeatStackCreateFailed(six.text_type(e))
else:
raise exception.HeatStackUpdateFailed(six.text_type(e))
return result
class OvercloudsController(rest.RestController):
"""REST controller for the Overcloud class."""
@ -156,7 +174,19 @@ class OvercloudsController(rest.RestController):
"""
LOG.debug('Creating overcloud: %s' % transfer_overcloud)
# FIXME(lsmola) This is just POC of creating a stack
# this has to be done properly with proper Work-flow abstraction of:
# step 1- build template and start stack-create
# step 2- put the right stack_id to the overcloud
# step 3- initialize the stack
# step 4- set the correct overcloud status
stack = process_stack(transfer_overcloud.attributes,
transfer_overcloud.counts,
get_overcloud_roles_dict(),
create=True)
# Persist to the database
transfer_overcloud.stack_id = stack['stack']['id']
db_overcloud = transfer_overcloud.to_db_model()
result = pecan.request.dbapi.create_overcloud(db_overcloud)
@ -164,15 +194,6 @@ class OvercloudsController(rest.RestController):
saved_overcloud =\
models.Overcloud.from_db_model(result)
# FIXME(lsmola) This is just POC of creating a stack
# this has to be done properly with proper Work-flow abstraction of:
# step one- build template and start stack-create
# step 2- put the right stack_id to the overcloud
# step 3- initialize the stack
# step 4- set the correct overcloud status
process_stack(saved_overcloud.attributes, result.counts,
create=True)
return saved_overcloud
@wsme.validate(models.Overcloud)
@ -210,10 +231,11 @@ class OvercloudsController(rest.RestController):
# FIXME(lsmola) This is just POC of updating a stack
# this probably should also have workflow
# step one- build template and stack-update
# step 1- build template and stack-update
# step 2- set the correct overcloud status
process_stack(updated_overcloud.attributes, updated_overcloud.counts,
create=True)
get_overcloud_roles_dict(), create=True)
return updated_overcloud
@ -231,7 +253,7 @@ 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
# step 1- 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)

View File

@ -71,7 +71,7 @@ class OvercloudTests(base.TestCase):
mock_db_get.assert_called_once_with(12345)
def test_parse_counts(self):
def test_parse_counts_overcloud_roles_explicit(self):
# Setup
overcloud_role_1 = db_models.OvercloudRole(
image_name='overcloud-compute')
@ -79,16 +79,19 @@ class OvercloudTests(base.TestCase):
overcloud_role_2 = db_models.OvercloudRole(
image_name='overcloud-block-storage')
mock_overcloud_roles = {1: overcloud_role_1, 2: overcloud_role_2}
overcloud_role_count_1 = db_models.OvercloudRoleCount(
overcloud_role_id=2, num_nodes=5, overcloud_role=overcloud_role_1)
overcloud_role_id=1, num_nodes=5)
overcloud_role_count_2 = db_models.OvercloudRoleCount(
overcloud_role_id=2, num_nodes=9, overcloud_role=overcloud_role_2)
overcloud_role_id=2, num_nodes=9)
mock_counts = [overcloud_role_count_1, overcloud_role_count_2]
# Test
result = overcloud.parse_counts(mock_counts)
result = overcloud.parse_counts(mock_counts,
overcloud_roles=mock_overcloud_roles)
# Verify
self.assertEqual(result, {'overcloud-compute': 5,
@ -121,7 +124,7 @@ class OvercloudTests(base.TestCase):
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': {},
'exists_stack.return_value': False,
'create_stack.return_value': True,
'create_stack.return_value': {'stack': {'id': '1'}},
})
)
def test_create_stack(self, mock_heat_client, mock_heat_merge_templates):
@ -129,10 +132,10 @@ 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)
self.assertEqual(response, {'stack': {'id': '1'}})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
@ -150,7 +153,7 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatStackCreateFailed,
overcloud.process_stack, {}, {}, True)
overcloud.process_stack, {}, {}, {}, create=True)
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
@ -167,8 +170,8 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.StackAlreadyCreated, overcloud.process_stack, {}, {},
True)
exception.StackAlreadyCreated, overcloud.process_stack, {}, {}, {},
create=True)
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
@ -186,18 +189,22 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatTemplateValidateFailed, overcloud.process_stack,
{}, {},
True)
{}, {}, {}, create=True)
@mock.patch('tuskar.db.sqlalchemy.api.Connection.get_overcloud_roles')
@mock.patch('tuskar.api.controllers.v1.overcloud.process_stack')
@mock.patch('tuskar.db.sqlalchemy.api.Connection.create_overcloud')
def test_post(self, mock_db_create, mock_process_stack):
def test_post(self, mock_db_create, mock_process_stack,
mock_get_overcloud_roles):
# Setup
create_me = {'name': 'new'}
fake_created = db_models.Overcloud(name='created')
mock_db_create.return_value = fake_created
mock_process_stack.return_value = None
mock_process_stack.return_value = {'stack': {'id': '1'}}
mock_get_overcloud_roles.return_value = [
mock.Mock(**{'id.return_value': 1, }),
mock.Mock(**{'id.return_value': 2, })]
# Test
response = self.app.post_json(URL_OVERCLOUDS, params=create_me)
@ -218,7 +225,7 @@ class OvercloudTests(base.TestCase):
'tuskar.heat.client.HeatClient.__new__', return_value=mock.Mock(**{
'validate_template.return_value': {},
'exists_stack.return_value': True,
'create_stack.return_value': True,
'update_stack.return_value': {'stack': {'id': '1'}},
})
)
def test_update_stack(self, mock_heat_client, mock_heat_merge_templates):
@ -226,10 +233,10 @@ 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)
self.assertEqual(response, {'stack': {'id': '1'}})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
@ -247,7 +254,7 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatStackUpdateFailed, overcloud.process_stack, {},
{})
{}, {})
@mock.patch('tuskar.heat.template_tools.merge_templates')
@mock.patch(
@ -264,7 +271,7 @@ 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(
@ -282,7 +289,7 @@ class OvercloudTests(base.TestCase):
# Test and Verify
self.assertRaises(
exception.HeatTemplateValidateFailed, overcloud.process_stack,
{}, {})
{}, {}, {})
@mock.patch('tuskar.api.controllers.v1.overcloud.process_stack')
@mock.patch('tuskar.db.sqlalchemy.api.Connection.update_overcloud')