Use RPC directly for software config operations
This change replaces heatclient REST calls with RPC calls when creating, fetching or deleting software configs. All resources can now request and RPC client with self.rpc_client() which will create and memoize an EngineClient instance. Change-Id: Id23749e672fd4154e3d9986e22b46fc038579d8e Partial-blueprint: software-config-trigger
This commit is contained in:
parent
bf437d3372
commit
7e1721dff3
|
@ -39,6 +39,7 @@ from heat.engine import rsrc_defn
|
|||
from heat.engine import scheduler
|
||||
from heat.engine import support
|
||||
from heat.openstack.common import log as logging
|
||||
from heat.rpc import client as rpc_client
|
||||
|
||||
cfg.CONF.import_opt('action_retry_limit', 'heat.common.config')
|
||||
|
||||
|
@ -177,11 +178,18 @@ class Resource(object):
|
|||
self._stored_properties_data = None
|
||||
self.created_time = None
|
||||
self.updated_time = None
|
||||
self._rpc_client = None
|
||||
|
||||
resource = stack.db_resource_get(name)
|
||||
if resource:
|
||||
self._load_data(resource)
|
||||
|
||||
def rpc_client(self):
|
||||
'''Return a client for making engine RPC calls.'''
|
||||
if not self._rpc_client:
|
||||
self._rpc_client = rpc_client.EngineClient()
|
||||
return self._rpc_client
|
||||
|
||||
def _load_data(self, resource):
|
||||
'''Load the resource state from its DB representation.'''
|
||||
self.resource_id = resource.nova_instance
|
||||
|
|
|
@ -30,6 +30,7 @@ from heat.engine import stack_user
|
|||
from heat.engine import support
|
||||
from heat.openstack.common import log as logging
|
||||
from heat.openstack.common import uuidutils
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
cfg.CONF.import_opt('instance_user', 'heat.common.config')
|
||||
|
||||
|
@ -469,6 +470,14 @@ class Server(stack_user.StackUser):
|
|||
return self.properties.get(
|
||||
self.SOFTWARE_CONFIG_TRANSPORT) == self.POLL_TEMP_URL
|
||||
|
||||
def get_software_config(self, ud_content):
|
||||
try:
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, ud_content)
|
||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||
except exception.NotFound:
|
||||
return ud_content
|
||||
|
||||
def handle_create(self):
|
||||
security_groups = self.properties.get(self.SECURITY_GROUPS)
|
||||
|
||||
|
@ -477,11 +486,7 @@ class Server(stack_user.StackUser):
|
|||
if self.user_data_software_config() or self.user_data_raw():
|
||||
if uuidutils.is_uuid_like(ud_content):
|
||||
# attempt to load the userdata from software config
|
||||
try:
|
||||
ud_content = self.heat().software_configs.get(
|
||||
ud_content).config
|
||||
except Exception as ex:
|
||||
self.client_plugin('heat').ignore_not_found(ex)
|
||||
ud_content = self.get_software_config(ud_content)
|
||||
|
||||
metadata = self.metadata_get(True) or {}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ from heat.common.template_format import yaml_dumper
|
|||
from heat.engine import properties
|
||||
from heat.engine.resources.software_config import software_config
|
||||
from heat.engine import support
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
|
||||
class CloudConfig(software_config.SoftwareConfig):
|
||||
|
@ -54,8 +55,8 @@ class CloudConfig(software_config.SoftwareConfig):
|
|||
cloud_config = yaml.dump(self.properties.get(
|
||||
self.CLOUD_CONFIG), Dumper=yaml_dumper)
|
||||
props[self.CONFIG] = '#cloud-config\n%s' % cloud_config
|
||||
sc = self.heat().software_configs.create(**props)
|
||||
self.resource_id_set(sc.id)
|
||||
sc = self.rpc_client().create_software_config(self.context, **props)
|
||||
self.resource_id_set(sc[rpc_api.SOFTWARE_CONFIG_ID])
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
|
|
|
@ -16,11 +16,13 @@ from email.mime.multipart import MIMEMultipart
|
|||
from email.mime.text import MIMEText
|
||||
import os
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine.resources.software_config import software_config
|
||||
from heat.engine import support
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
|
||||
class MultipartMime(software_config.SoftwareConfig):
|
||||
|
@ -95,8 +97,8 @@ class MultipartMime(software_config.SoftwareConfig):
|
|||
def handle_create(self):
|
||||
props = {self.NAME: self.physical_resource_name()}
|
||||
props[self.CONFIG] = self.get_message()
|
||||
sc = self.heat().software_configs.create(**props)
|
||||
self.resource_id_set(sc.id)
|
||||
sc = self.rpc_client().create_software_config(self.context, **props)
|
||||
self.resource_id_set(sc[rpc_api.SOFTWARE_CONFIG_ID])
|
||||
|
||||
def get_message(self):
|
||||
if self.message:
|
||||
|
@ -107,10 +109,14 @@ class MultipartMime(software_config.SoftwareConfig):
|
|||
config = item.get(self.CONFIG)
|
||||
part_type = item.get(self.TYPE, self.TEXT)
|
||||
part = config
|
||||
|
||||
try:
|
||||
part = self.heat().software_configs.get(config).config
|
||||
except Exception as ex:
|
||||
self.client_plugin().ignore_not_found(ex)
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, self.resource_id)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
else:
|
||||
part = sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||
|
||||
if part_type == self.MULTIPART:
|
||||
self._append_multiparts(subparts, part)
|
||||
|
|
|
@ -18,6 +18,7 @@ from heat.engine import properties
|
|||
from heat.engine import resource
|
||||
from heat.engine.resources.software_config import software_config as sc
|
||||
from heat.engine import support
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
|
||||
class SoftwareComponent(sc.SoftwareConfig):
|
||||
|
@ -116,8 +117,8 @@ class SoftwareComponent(sc.SoftwareConfig):
|
|||
# set 'group' to enable component processing by in-instance hook
|
||||
props[self.GROUP] = 'component'
|
||||
|
||||
sc = self.heat().software_configs.create(**props)
|
||||
self.resource_id_set(sc.id)
|
||||
sc = self.rpc_client().create_software_config(self.context, **props)
|
||||
self.resource_id_set(sc[rpc_api.SOFTWARE_CONFIG_ID])
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
'''
|
||||
|
@ -129,14 +130,13 @@ class SoftwareComponent(sc.SoftwareConfig):
|
|||
'''
|
||||
if name == self.CONFIGS_ATTR and self.resource_id:
|
||||
try:
|
||||
config = self.heat().software_configs.get(self.resource_id).\
|
||||
config
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, self.resource_id)
|
||||
# configs list is stored in 'config' property of parent class
|
||||
# (see handle_create)
|
||||
return config.get(self.CONFIGS)
|
||||
except Exception as ex:
|
||||
if self.client_plugin().is_not_found(ex):
|
||||
return None
|
||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG].get(self.CONFIGS)
|
||||
except exception.NotFound:
|
||||
return None
|
||||
|
||||
def validate(self):
|
||||
'''Validate SoftwareComponent properties consistency.'''
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
from heat.engine import attributes
|
||||
from heat.engine import constraints
|
||||
|
@ -18,6 +19,7 @@ from heat.engine import properties
|
|||
from heat.engine import resource
|
||||
from heat.engine import support
|
||||
from heat.openstack.common import log as logging
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -152,14 +154,12 @@ class SoftwareConfig(resource.Resource):
|
|||
),
|
||||
}
|
||||
|
||||
default_client_name = 'heat'
|
||||
|
||||
def handle_create(self):
|
||||
props = dict(self.properties)
|
||||
props[self.NAME] = self.physical_resource_name()
|
||||
|
||||
sc = self.heat().software_configs.create(**props)
|
||||
self.resource_id_set(sc.id)
|
||||
sc = self.rpc_client().create_software_config(self.context, **props)
|
||||
self.resource_id_set(sc[rpc_api.SOFTWARE_CONFIG_ID])
|
||||
|
||||
def handle_delete(self):
|
||||
|
||||
|
@ -167,9 +167,10 @@ class SoftwareConfig(resource.Resource):
|
|||
return
|
||||
|
||||
try:
|
||||
self.heat().software_configs.delete(self.resource_id)
|
||||
except Exception as ex:
|
||||
self.client_plugin().ignore_not_found(ex)
|
||||
self.rpc_client().delete_software_config(
|
||||
self.context, self.resource_id)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
'''
|
||||
|
@ -178,11 +179,11 @@ class SoftwareConfig(resource.Resource):
|
|||
'''
|
||||
if name == self.CONFIG_ATTR and self.resource_id:
|
||||
try:
|
||||
return self.heat().software_configs.get(
|
||||
self.resource_id).config
|
||||
except Exception as ex:
|
||||
if self.client_plugin().is_not_found(ex):
|
||||
return None
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, self.resource_id)
|
||||
return sc[rpc_api.SOFTWARE_CONFIG_CONFIG]
|
||||
except exception.NotFound:
|
||||
return None
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
|
|
|
@ -26,6 +26,7 @@ from heat.engine.resources.software_config import software_config as sc
|
|||
from heat.engine import signal_responder
|
||||
from heat.engine import support
|
||||
from heat.openstack.common import log as logging
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -194,23 +195,26 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
|
||||
def _delete_derived_config(self, derived_config_id):
|
||||
try:
|
||||
self.heat().software_configs.delete(derived_config_id)
|
||||
except Exception as ex:
|
||||
self.client_plugin().ignore_not_found(ex)
|
||||
self.rpc_client().delete_software_config(
|
||||
self.context, derived_config_id)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
|
||||
def _get_derived_config(self, action, source_config):
|
||||
|
||||
derived_params = self._build_derived_config_params(
|
||||
action, source_config.to_dict())
|
||||
derived_config = self.heat().software_configs.create(**derived_params)
|
||||
return derived_config.id
|
||||
action, source_config)
|
||||
derived_config = self.rpc_client().create_software_config(
|
||||
self.context, **derived_params)
|
||||
return derived_config[rpc_api.SOFTWARE_CONFIG_ID]
|
||||
|
||||
def _handle_action(self, action):
|
||||
config_id = self.properties.get(self.CONFIG)
|
||||
config = self.heat().software_configs.get(config_id)
|
||||
config = self.rpc_client().show_software_config(
|
||||
self.context, config_id)
|
||||
|
||||
if action not in self.properties[self.DEPLOY_ACTIONS]\
|
||||
and not config.group == 'component':
|
||||
and not config[rpc_api.SOFTWARE_CONFIG_GROUP] == 'component':
|
||||
return
|
||||
|
||||
props = self._build_properties(
|
||||
|
@ -430,7 +434,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
|
||||
def handle_signal(self, details):
|
||||
sd = self.heat().software_deployments.get(self.resource_id)
|
||||
sc = self.heat().software_configs.get(self.properties[self.CONFIG])
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, self.properties[self.CONFIG])
|
||||
if not sd.status == self.IN_PROGRESS:
|
||||
# output values are only expected when in an IN_PROGRESS state
|
||||
return
|
||||
|
@ -450,7 +455,7 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
else:
|
||||
event_reason = 'deployment succeeded'
|
||||
|
||||
for output in sc.outputs or []:
|
||||
for output in sc[rpc_api.SOFTWARE_CONFIG_OUTPUTS] or []:
|
||||
out_key = output['name']
|
||||
if out_key in details:
|
||||
ov[out_key] = details[out_key]
|
||||
|
@ -486,8 +491,10 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
|
||||
# Since there is no value for this key yet, check the output schemas
|
||||
# to find out if the key is valid
|
||||
sc = self.heat().software_configs.get(self.properties[self.CONFIG])
|
||||
output_keys = [output['name'] for output in sc.outputs]
|
||||
sc = self.rpc_client().show_software_config(
|
||||
self.context, self.properties[self.CONFIG])
|
||||
outputs = sc[rpc_api.SOFTWARE_CONFIG_OUTPUTS] or []
|
||||
output_keys = [output['name'] for output in outputs]
|
||||
if key not in output_keys and key not in self.ATTRIBUTES:
|
||||
raise exception.InvalidTemplateAttribute(resource=self.name,
|
||||
key=key)
|
||||
|
|
|
@ -38,9 +38,8 @@ class CloudConfigTest(common.HeatTestCase):
|
|||
'Properties': self.properties
|
||||
}}}))
|
||||
self.config = self.stack['config_mysql']
|
||||
heat = mock.MagicMock()
|
||||
self.config.heat = heat
|
||||
self.software_configs = heat.return_value.software_configs
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.config._rpc_client = self.rpc_client
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = cc.resource_mapping()
|
||||
|
@ -50,11 +49,10 @@ class CloudConfigTest(common.HeatTestCase):
|
|||
self.assertIsInstance(self.config, cc.CloudConfig)
|
||||
|
||||
def test_handle_create(self):
|
||||
sc = mock.MagicMock()
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
sc.id = config_id
|
||||
self.software_configs.create.return_value = sc
|
||||
value = {'id': config_id}
|
||||
self.rpc_client.create_software_config.return_value = value
|
||||
self.config.handle_create()
|
||||
self.assertEqual(config_id, self.config.resource_id)
|
||||
kwargs = self.software_configs.create.call_args[1]
|
||||
kwargs = self.rpc_client.create_software_config.call_args[1]
|
||||
self.assertEqual('#cloud-config\n{foo: bar}\n', kwargs['config'])
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
import email
|
||||
|
||||
import heatclient.exc as exc
|
||||
import mock
|
||||
|
||||
from heat.common import exception as exc
|
||||
from heat.engine import parser
|
||||
from heat.engine.resources.software_config import multi_part as mp
|
||||
from heat.engine import template
|
||||
|
@ -43,9 +43,8 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
'parts': parts
|
||||
}}}}))
|
||||
self.config = stack['config_mysql']
|
||||
heat = mock.MagicMock()
|
||||
self.config.heat = heat
|
||||
self.software_configs = heat.return_value.software_configs
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.config._rpc_client = self.rpc_client
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = mp.resource_mapping()
|
||||
|
@ -55,13 +54,12 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
self.assertIsInstance(self.config, mp.MultipartMime)
|
||||
|
||||
def test_handle_create(self):
|
||||
sc = mock.MagicMock()
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
sc.id = config_id
|
||||
self.software_configs.create.return_value = sc
|
||||
sc = {'id': config_id}
|
||||
self.rpc_client.create_software_config.return_value = sc
|
||||
self.config.handle_create()
|
||||
self.assertEqual(config_id, self.config.resource_id)
|
||||
args = self.software_configs.create.call_args[1]
|
||||
args = self.rpc_client.create_software_config.call_args[1]
|
||||
self.assertEqual(self.config.message, args['config'])
|
||||
|
||||
def test_get_message_not_none(self):
|
||||
|
@ -82,7 +80,9 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
'type': 'text'
|
||||
}]
|
||||
self.init_config(parts=parts)
|
||||
self.software_configs.get.return_value.config = '#!/bin/bash'
|
||||
self.rpc_client.show_software_config.return_value = {
|
||||
'config': '#!/bin/bash'
|
||||
}
|
||||
result = self.config.get_message()
|
||||
message = email.message_from_string(result)
|
||||
self.assertTrue(message.is_multipart())
|
||||
|
@ -96,7 +96,7 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
'type': 'text'
|
||||
}]
|
||||
self.init_config(parts=parts)
|
||||
self.software_configs.get.side_effect = exc.HTTPNotFound()
|
||||
self.rpc_client.show_software_config.side_effect = exc.NotFound()
|
||||
result = self.config.get_message()
|
||||
message = email.message_from_string(result)
|
||||
self.assertTrue(message.is_multipart())
|
||||
|
@ -111,7 +111,9 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
'filename': '/opt/stack/configure.d/55-heat-config'
|
||||
}]
|
||||
self.init_config(parts=parts)
|
||||
self.software_configs.get.return_value.config = '#!/bin/bash'
|
||||
self.rpc_client.show_software_config.return_value = {
|
||||
'config': '#!/bin/bash'
|
||||
}
|
||||
result = self.config.get_message()
|
||||
message = email.message_from_string(result)
|
||||
self.assertTrue(message.is_multipart())
|
||||
|
@ -138,7 +140,11 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
'type': 'multipart'
|
||||
}]
|
||||
self.init_config(parts=parts)
|
||||
self.software_configs.get.return_value.config = multipart
|
||||
|
||||
self.rpc_client.show_software_config.return_value = {
|
||||
'config': multipart
|
||||
}
|
||||
|
||||
result = self.config.get_message()
|
||||
message = email.message_from_string(result)
|
||||
self.assertTrue(message.is_multipart())
|
||||
|
@ -155,7 +161,9 @@ class MultipartMimeTest(common.HeatTestCase):
|
|||
{'config': '9cab10ef-16ce-4be9-8b25-a67b7313eddb',
|
||||
'type': 'text'}]
|
||||
self.init_config(parts=parts)
|
||||
self.software_configs.get.return_value.config = '#!/bin/bash'
|
||||
self.rpc_client.show_software_config.return_value = {
|
||||
'config': '#!/bin/bash'
|
||||
}
|
||||
result = self.config.get_message()
|
||||
message = email.message_from_string(result)
|
||||
self.assertTrue(message.is_multipart())
|
||||
|
|
|
@ -26,7 +26,6 @@ from heat.common.i18n import _
|
|||
from heat.common import template_format
|
||||
from heat.db import api as db_api
|
||||
from heat.engine.clients.os import glance
|
||||
from heat.engine.clients.os import heat_plugin
|
||||
from heat.engine.clients.os import nova
|
||||
from heat.engine.clients.os import swift
|
||||
from heat.engine import environment
|
||||
|
@ -531,12 +530,11 @@ class ServersTest(common.HeatTestCase):
|
|||
server = servers.Server('WebServer',
|
||||
resource_defns['WebServer'], stack)
|
||||
|
||||
self.m.StubOutWithMock(heat_plugin.HeatClientPlugin, '_create')
|
||||
heat_client = mock.Mock()
|
||||
heat_plugin.HeatClientPlugin._create().AndReturn(heat_client)
|
||||
sc = mock.Mock()
|
||||
sc.config = 'wordpress from config'
|
||||
heat_client.software_configs.get.return_value = sc
|
||||
self.rpc_client = mock.MagicMock()
|
||||
server._rpc_client = self.rpc_client
|
||||
|
||||
sc = {'config': 'wordpress from config'}
|
||||
self.rpc_client.show_software_config.return_value = sc
|
||||
|
||||
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
||||
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
||||
|
@ -572,11 +570,10 @@ class ServersTest(common.HeatTestCase):
|
|||
server = servers.Server('WebServer',
|
||||
resource_defns['WebServer'], stack)
|
||||
|
||||
self.m.StubOutWithMock(heat_plugin.HeatClientPlugin, '_create')
|
||||
heat_client = mock.Mock()
|
||||
heat_plugin.HeatClientPlugin._create().AndReturn(heat_client)
|
||||
heat_client.software_configs.get.side_effect = \
|
||||
heat_plugin.exc.HTTPNotFound()
|
||||
self.rpc_client = mock.MagicMock()
|
||||
server._rpc_client = self.rpc_client
|
||||
|
||||
self.rpc_client.show_software_config.side_effect = exception.NotFound
|
||||
|
||||
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
||||
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
||||
|
|
|
@ -14,14 +14,13 @@
|
|||
import mock
|
||||
import six
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import exception as exc
|
||||
from heat.common import template_format
|
||||
from heat.engine.resources.software_config import software_component as sc
|
||||
from heat.engine import stack
|
||||
from heat.engine import template
|
||||
from heat.tests import common
|
||||
from heat.tests import utils
|
||||
from heatclient.exc import HTTPNotFound
|
||||
|
||||
|
||||
class SoftwareComponentTest(common.HeatTestCase):
|
||||
|
@ -58,11 +57,8 @@ class SoftwareComponentTest(common.HeatTestCase):
|
|||
self.ctx, 'software_component_test_stack',
|
||||
template.Template(self.template))
|
||||
self.component = self.stack['mysql_component']
|
||||
heat = mock.MagicMock()
|
||||
self.heatclient = mock.MagicMock()
|
||||
self.component.heat = heat
|
||||
heat.return_value = self.heatclient
|
||||
self.software_configs = self.heatclient.software_configs
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.component._rpc_client = self.rpc_client
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = sc.resource_mapping()
|
||||
|
@ -72,10 +68,9 @@ class SoftwareComponentTest(common.HeatTestCase):
|
|||
self.assertIsInstance(self.component, sc.SoftwareComponent)
|
||||
|
||||
def test_handle_create(self):
|
||||
value = mock.MagicMock()
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
value.id = config_id
|
||||
self.software_configs.create.return_value = value
|
||||
value = {'id': config_id}
|
||||
self.rpc_client.create_software_config.return_value = value
|
||||
self.component.handle_create()
|
||||
self.assertEqual(config_id, self.component.resource_id)
|
||||
|
||||
|
@ -84,9 +79,9 @@ class SoftwareComponentTest(common.HeatTestCase):
|
|||
self.assertIsNone(self.component.handle_delete())
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
self.component.resource_id = config_id
|
||||
self.software_configs.delete.return_value = None
|
||||
self.rpc_client.delete_software_config.return_value = None
|
||||
self.assertIsNone(self.component.handle_delete())
|
||||
self.software_configs.delete.side_effect = HTTPNotFound()
|
||||
self.rpc_client.delete_software_config.side_effect = exc.NotFound
|
||||
self.assertIsNone(self.component.handle_delete())
|
||||
|
||||
def test_resolve_attribute(self):
|
||||
|
@ -94,14 +89,13 @@ class SoftwareComponentTest(common.HeatTestCase):
|
|||
self.component.resource_id = None
|
||||
self.assertIsNone(self.component._resolve_attribute('configs'))
|
||||
self.component.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
value = mock.MagicMock()
|
||||
configs = self.\
|
||||
template['resources']['mysql_component']['properties']['configs']
|
||||
# configs list is stored in 'config' property of SoftwareConfig
|
||||
value.config = {'configs': configs}
|
||||
self.software_configs.get.return_value = value
|
||||
value = {'config': {'configs': configs}}
|
||||
self.rpc_client.show_software_config.return_value = value
|
||||
self.assertEqual(configs, self.component._resolve_attribute('configs'))
|
||||
self.software_configs.get.side_effect = HTTPNotFound()
|
||||
self.rpc_client.show_software_config.side_effect = exc.NotFound
|
||||
self.assertIsNone(self.component._resolve_attribute('configs'))
|
||||
|
||||
|
||||
|
@ -160,7 +154,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
echo CREATE $foo
|
||||
tool: script
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='Unknown Property config')
|
||||
),
|
||||
(
|
||||
|
@ -172,7 +166,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
inputs:
|
||||
- name: foo
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='Property configs not assigned')
|
||||
),
|
||||
# do not test until bug #1350840
|
||||
|
@ -199,7 +193,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
config: #!/bin/bash
|
||||
tool: script
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='is not a list')
|
||||
),
|
||||
(
|
||||
|
@ -213,7 +207,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
config: #!/bin/bash
|
||||
tool: script
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='actions length (0) is out of range '
|
||||
'(min: 1, max: None)')
|
||||
),
|
||||
|
@ -231,7 +225,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
config: #!/bin/bash
|
||||
tool: script
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='Defining more than one configuration for the same '
|
||||
'action in SoftwareComponent "component" is not '
|
||||
'allowed.')
|
||||
|
@ -250,7 +244,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
config: #!/bin/bash
|
||||
tool: script
|
||||
''',
|
||||
err=exception.StackValidationFailed,
|
||||
err=exc.StackValidationFailed,
|
||||
err_msg='Defining more than one configuration for the same '
|
||||
'action in SoftwareComponent "component" is not '
|
||||
'allowed.')
|
||||
|
@ -272,11 +266,7 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
|
|||
self.ctx, 'software_component_test_stack',
|
||||
template.Template(self.template))
|
||||
self.component = self.stack['component']
|
||||
heat = mock.MagicMock()
|
||||
self.heatclient = mock.MagicMock()
|
||||
self.component.heat = heat
|
||||
heat.return_value = self.heatclient
|
||||
self.software_configs = self.heatclient.software_configs
|
||||
self.component._rpc_client = mock.MagicMock()
|
||||
|
||||
def test_properties_schema(self):
|
||||
if self.err:
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from heatclient.exc import HTTPNotFound
|
||||
import mock
|
||||
|
||||
from heat.common import exception as exc
|
||||
from heat.engine import parser
|
||||
from heat.engine.resources.software_config import software_config as sc
|
||||
from heat.engine import template
|
||||
|
@ -43,11 +43,8 @@ class SoftwareConfigTest(common.HeatTestCase):
|
|||
'Properties': self.properties
|
||||
}}}))
|
||||
self.config = self.stack['config_mysql']
|
||||
heat = mock.MagicMock()
|
||||
self.heatclient = mock.MagicMock()
|
||||
self.config.heat = heat
|
||||
heat.return_value = self.heatclient
|
||||
self.software_configs = self.heatclient.software_configs
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.config._rpc_client = self.rpc_client
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = sc.resource_mapping()
|
||||
|
@ -57,10 +54,9 @@ class SoftwareConfigTest(common.HeatTestCase):
|
|||
self.assertIsInstance(self.config, sc.SoftwareConfig)
|
||||
|
||||
def test_handle_create(self):
|
||||
value = mock.MagicMock()
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
value.id = config_id
|
||||
self.software_configs.create.return_value = value
|
||||
value = {'id': config_id}
|
||||
self.rpc_client.create_software_config.return_value = value
|
||||
self.config.handle_create()
|
||||
self.assertEqual(config_id, self.config.resource_id)
|
||||
|
||||
|
@ -69,9 +65,9 @@ class SoftwareConfigTest(common.HeatTestCase):
|
|||
self.assertIsNone(self.config.handle_delete())
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
self.config.resource_id = config_id
|
||||
self.software_configs.delete.return_value = None
|
||||
self.rpc_client.delete_software_config.return_value = None
|
||||
self.assertIsNone(self.config.handle_delete())
|
||||
self.software_configs.delete.side_effect = HTTPNotFound()
|
||||
self.rpc_client.delete_software_config.side_effect = exc.NotFound
|
||||
self.assertIsNone(self.config.handle_delete())
|
||||
|
||||
def test_resolve_attribute(self):
|
||||
|
@ -79,10 +75,9 @@ class SoftwareConfigTest(common.HeatTestCase):
|
|||
self.config.resource_id = None
|
||||
self.assertIsNone(self.config._resolve_attribute('config'))
|
||||
self.config.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
value = mock.MagicMock()
|
||||
value.config = '#!/bin/bash'
|
||||
self.software_configs.get.return_value = value
|
||||
value = {'config': '#!/bin/bash'}
|
||||
self.rpc_client.show_software_config.return_value = value
|
||||
self.assertEqual(
|
||||
'#!/bin/bash', self.config._resolve_attribute('config'))
|
||||
self.software_configs.get.side_effect = HTTPNotFound()
|
||||
self.rpc_client.show_software_config.side_effect = exc.NotFound
|
||||
self.assertEqual(None, self.config._resolve_attribute('config'))
|
||||
|
|
|
@ -17,7 +17,7 @@ import copy
|
|||
import mock
|
||||
import six
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import exception as exc
|
||||
from heat.common.i18n import _
|
||||
from heat.engine import parser
|
||||
from heat.engine.resources.software_config import software_deployment as sd
|
||||
|
@ -117,10 +117,13 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
get_signed_url.return_value = 'http://192.0.2.2/signed_url'
|
||||
|
||||
self.deployment = self.stack['deployment_mysql']
|
||||
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.deployment._rpc_client = self.rpc_client
|
||||
|
||||
heat = mock.MagicMock()
|
||||
self.deployment.heat = heat
|
||||
self.deployments = heat.return_value.software_deployments
|
||||
self.software_configs = heat.return_value.software_configs
|
||||
|
||||
def test_validate(self):
|
||||
template = dict(self.template_with_server)
|
||||
|
@ -138,7 +141,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
props['user_data_format'] = 'RAW'
|
||||
self._create_stack(template)
|
||||
sd = self.deployment
|
||||
err = self.assertRaises(exception.StackValidationFailed, sd.validate)
|
||||
err = self.assertRaises(exc.StackValidationFailed, sd.validate)
|
||||
self.assertEqual("Resource server's property "
|
||||
"user_data_format should be set to "
|
||||
"SOFTWARE_CONFIG since there are "
|
||||
|
@ -149,7 +152,6 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
self.assertIsInstance(self.deployment, sd.SoftwareDeployment)
|
||||
|
||||
def mock_software_config(self):
|
||||
sc = mock.MagicMock()
|
||||
config = {
|
||||
'id': '48e8ade1-9196-42d5-89a2-f709fde42632',
|
||||
'group': 'Test::Group',
|
||||
|
@ -167,14 +169,10 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
}],
|
||||
'outputs': [],
|
||||
}
|
||||
sc.to_dict.return_value = config
|
||||
sc.group = 'Test::Group'
|
||||
sc.config = config['config']
|
||||
self.software_configs.get.return_value = sc
|
||||
return sc
|
||||
self.rpc_client.show_software_config.return_value = config
|
||||
return config
|
||||
|
||||
def mock_software_component(self):
|
||||
sc = mock.MagicMock()
|
||||
config = {
|
||||
'id': '48e8ade1-9196-42d5-89a2-f709fde42632',
|
||||
'group': 'component',
|
||||
|
@ -220,16 +218,12 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
}],
|
||||
'outputs': [],
|
||||
}
|
||||
sc.to_dict.return_value = config
|
||||
sc.group = 'component'
|
||||
sc.config = config['config']
|
||||
self.software_configs.get.return_value = sc
|
||||
return sc
|
||||
self.rpc_client.show_software_config.return_value = config
|
||||
return config
|
||||
|
||||
def mock_derived_software_config(self):
|
||||
sc = mock.MagicMock()
|
||||
sc.id = '9966c8e7-bc9c-42de-aa7d-f2447a952cb2'
|
||||
self.software_configs.create.return_value = sc
|
||||
sc = {'id': '9966c8e7-bc9c-42de-aa7d-f2447a952cb2'}
|
||||
self.rpc_client.create_software_config.return_value = sc
|
||||
return sc
|
||||
|
||||
def mock_deployment(self):
|
||||
|
@ -290,11 +284,11 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
}],
|
||||
'options': {},
|
||||
'outputs': []
|
||||
}, self.software_configs.create.call_args[1])
|
||||
}, self.rpc_client.create_software_config.call_args[1])
|
||||
|
||||
self.assertEqual(
|
||||
{'action': 'CREATE',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'COMPLETE',
|
||||
|
@ -381,11 +375,11 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
}],
|
||||
'options': {},
|
||||
'outputs': []
|
||||
}, self.software_configs.create.call_args[1])
|
||||
}, self.rpc_client.create_software_config.call_args[1])
|
||||
|
||||
self.assertEqual(
|
||||
{'action': 'CREATE',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'COMPLETE',
|
||||
|
@ -404,7 +398,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
args = self.deployments.create.call_args[1]
|
||||
self.assertEqual(
|
||||
{'action': 'CREATE',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
|
@ -449,7 +443,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
sd.status = self.deployment.FAILED
|
||||
sd.status_reason = 'something wrong'
|
||||
err = self.assertRaises(
|
||||
exception.Error, self.deployment.check_create_complete, sd)
|
||||
exc.Error, self.deployment.check_create_complete, sd)
|
||||
self.assertEqual(
|
||||
'Deployment to server failed: something wrong', six.text_type(err))
|
||||
|
||||
|
@ -479,7 +473,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
args = sd.update.call_args[1]
|
||||
self.assertEqual({
|
||||
'action': 'DELETE',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
|
@ -499,14 +493,15 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
self.mock_software_config()
|
||||
derived_sc = self.mock_derived_software_config()
|
||||
sd = self.mock_deployment()
|
||||
sd.config_id = derived_sc.id
|
||||
sd.config_id = derived_sc['id']
|
||||
self.deployments.get.return_value = sd
|
||||
|
||||
sd.delete.side_effect = HTTPNotFound()
|
||||
self.software_configs.delete.side_effect = HTTPNotFound()
|
||||
self.rpc_client.delete_software_config.side_effect = exc.NotFound
|
||||
self.assertIsNone(self.deployment.handle_delete())
|
||||
self.assertEqual(
|
||||
(derived_sc.id,), self.software_configs.delete.call_args[0])
|
||||
(self.ctx, derived_sc['id']),
|
||||
self.rpc_client.delete_software_config.call_args[0])
|
||||
|
||||
def test_handle_delete_none(self):
|
||||
self._create_stack(self.template)
|
||||
|
@ -539,13 +534,14 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
self.deployment.handle_update(
|
||||
json_snippet=snippet, tmpl_diff=None, prop_diff=prop_diff)
|
||||
self.assertEqual(
|
||||
(config_id,), self.software_configs.get.call_args[0])
|
||||
(self.ctx, config_id),
|
||||
self.rpc_client.show_software_config.call_args[0])
|
||||
|
||||
args = self.deployments.get.call_args[0]
|
||||
self.assertEqual(1, len(args))
|
||||
self.assertIn(sd.id, args)
|
||||
args = sd.update.call_args[1]
|
||||
self.assertEqual(derived_sc.id, args['config_id'])
|
||||
self.assertEqual(derived_sc['id'], args['config_id'])
|
||||
|
||||
def test_handle_suspend_resume(self):
|
||||
self._create_stack(self.template_delete_suspend_resume)
|
||||
|
@ -564,7 +560,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
args = sd.update.call_args[1]
|
||||
self.assertEqual({
|
||||
'action': 'SUSPEND',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
|
@ -583,7 +579,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
args = sd.update.call_args[1]
|
||||
self.assertEqual({
|
||||
'action': 'RESUME',
|
||||
'config_id': derived_sc.id,
|
||||
'config_id': derived_sc['id'],
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
|
@ -599,16 +595,18 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
def test_handle_signal_ok_zero(self):
|
||||
self._create_stack(self.template)
|
||||
sd = mock.MagicMock()
|
||||
sc = mock.MagicMock()
|
||||
sc.outputs = [{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed',
|
||||
'error_output': True}]
|
||||
sc = {
|
||||
'outputs': [
|
||||
{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed', 'error_output': True}
|
||||
]
|
||||
}
|
||||
sd.output_values = {}
|
||||
sd.status = self.deployment.IN_PROGRESS
|
||||
sd.update.return_value = None
|
||||
self.deployments.get.return_value = sd
|
||||
self.software_configs.get.return_value = sc
|
||||
self.rpc_client.show_software_config.return_value = sc
|
||||
details = {
|
||||
'foo': 'bar',
|
||||
'deploy_status_code': 0
|
||||
|
@ -630,16 +628,18 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
def test_handle_signal_ok_str_zero(self):
|
||||
self._create_stack(self.template)
|
||||
sd = mock.MagicMock()
|
||||
sc = mock.MagicMock()
|
||||
sc.outputs = [{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed',
|
||||
'error_output': True}]
|
||||
sc = {
|
||||
'outputs': [
|
||||
{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed', 'error_output': True}
|
||||
]
|
||||
}
|
||||
sd.output_values = {}
|
||||
sd.status = self.deployment.IN_PROGRESS
|
||||
sd.update.return_value = None
|
||||
self.deployments.get.return_value = sd
|
||||
self.software_configs.get.return_value = sc
|
||||
self.rpc_client.show_software_config.return_value = sc
|
||||
details = {
|
||||
'foo': 'bar',
|
||||
'deploy_status_code': '0'
|
||||
|
@ -661,16 +661,18 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
def test_handle_signal_failed(self):
|
||||
self._create_stack(self.template)
|
||||
sd = mock.MagicMock()
|
||||
sc = mock.MagicMock()
|
||||
sc.outputs = [{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed',
|
||||
'error_output': True}]
|
||||
sc = {
|
||||
'outputs': [
|
||||
{'name': 'foo'},
|
||||
{'name': 'foo2'},
|
||||
{'name': 'failed', 'error_output': True}
|
||||
]
|
||||
}
|
||||
sd.output_values = {}
|
||||
sd.status = self.deployment.IN_PROGRESS
|
||||
sd.update.return_value = None
|
||||
self.deployments.get.return_value = sd
|
||||
self.software_configs.get.return_value = sc
|
||||
self.rpc_client.show_software_config.return_value = sc
|
||||
details = {'failed': 'no enough memory found.'}
|
||||
ret = self.deployment.handle_signal(details)
|
||||
self.assertEqual('deployment failed', ret)
|
||||
|
@ -760,7 +762,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
sd.outputs = []
|
||||
sd.output_values = {'foo': 'bar'}
|
||||
err = self.assertRaises(
|
||||
exception.InvalidTemplateAttribute,
|
||||
exc.InvalidTemplateAttribute,
|
||||
self.deployment.FnGetAtt, 'foo2')
|
||||
self.assertEqual(
|
||||
'The Referenced Attribute (deployment_mysql foo2) is incorrect.',
|
||||
|
|
|
@ -44,9 +44,8 @@ class StructuredConfigTestJSON(common.HeatTestCase):
|
|||
self.ctx, 'software_config_test_stack',
|
||||
template.Template(self.template))
|
||||
self.config = self.stack['config_mysql']
|
||||
heat = mock.MagicMock()
|
||||
self.config.heat = heat
|
||||
self.software_configs = heat.return_value.software_configs
|
||||
self.rpc_client = mock.MagicMock()
|
||||
self.config._rpc_client = self.rpc_client
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = sc.resource_mapping()
|
||||
|
@ -60,13 +59,12 @@ class StructuredConfigTestJSON(common.HeatTestCase):
|
|||
self.assertIsInstance(self.config, sc.StructuredConfig)
|
||||
|
||||
def test_handle_create(self):
|
||||
stc = mock.MagicMock()
|
||||
config_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
stc.id = config_id
|
||||
self.software_configs.create.return_value = stc
|
||||
value = {'id': config_id}
|
||||
self.rpc_client.create_software_config.return_value = value
|
||||
self.config.handle_create()
|
||||
self.assertEqual(config_id, self.config.resource_id)
|
||||
kwargs = self.software_configs.create.call_args[1]
|
||||
kwargs = self.rpc_client.create_software_config.call_args[1]
|
||||
self.assertEqual(self.stored_config, kwargs['config'])
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue