Move software service logic to own module
The size of EngineService is starting to affect maintainability. This change creates service_software_config.SoftwareConfigService and moves all the software config service method implementations into it. Software config calls to EngineService are delegated to SoftwareConfigService. Unit tests remain in test_engine_service to include the EngineService entrypoint methods in the test coverage. Change-Id: Icf51dfd35423ac33a9126731862a90525c17306c Related-Blueprint: software-config-trigger
This commit is contained in:
parent
fee3937550
commit
29b69028e5
|
@ -21,13 +21,9 @@ import eventlet
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
from osprofiler import profiler
|
||||
import requests
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import webob
|
||||
|
||||
from heat.common import context
|
||||
|
@ -48,6 +44,7 @@ from heat.engine import event as evt
|
|||
from heat.engine import parameter_groups
|
||||
from heat.engine import properties
|
||||
from heat.engine import resources
|
||||
from heat.engine import service_software_config
|
||||
from heat.engine import service_stack_watch
|
||||
from heat.engine import stack as parser
|
||||
from heat.engine import stack_lock
|
||||
|
@ -282,6 +279,7 @@ class EngineService(service.Service):
|
|||
self.service_id = None
|
||||
self.manage_thread_grp = None
|
||||
self._rpc_server = None
|
||||
self.software_config = service_software_config.SoftwareConfigService()
|
||||
|
||||
if cfg.CONF.instance_user:
|
||||
warnings.warn('The "instance_user" option in heat.conf is '
|
||||
|
@ -1408,234 +1406,80 @@ class EngineService(service.Service):
|
|||
|
||||
@context.request_context
|
||||
def show_software_config(self, cnxt, config_id):
|
||||
sc = db_api.software_config_get(cnxt, config_id)
|
||||
return api.format_software_config(sc)
|
||||
return self.software_config.show_software_config(cnxt, config_id)
|
||||
|
||||
@context.request_context
|
||||
def create_software_config(self, cnxt, group, name, config,
|
||||
inputs, outputs, options):
|
||||
|
||||
sc = db_api.software_config_create(cnxt, {
|
||||
'group': group,
|
||||
'name': name,
|
||||
'config': {
|
||||
'inputs': inputs,
|
||||
'outputs': outputs,
|
||||
'options': options,
|
||||
'config': config
|
||||
},
|
||||
'tenant': cnxt.tenant_id})
|
||||
return api.format_software_config(sc)
|
||||
return self.software_config.create_software_config(
|
||||
cnxt,
|
||||
group=group,
|
||||
name=name,
|
||||
config=config,
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
options=options)
|
||||
|
||||
@context.request_context
|
||||
def delete_software_config(self, cnxt, config_id):
|
||||
db_api.software_config_delete(cnxt, config_id)
|
||||
return self.software_config.delete_software_config(cnxt, config_id)
|
||||
|
||||
@context.request_context
|
||||
def list_software_deployments(self, cnxt, server_id):
|
||||
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
|
||||
result = [api.format_software_deployment(sd) for sd in all_sd]
|
||||
return result
|
||||
return self.software_config.list_software_deployments(
|
||||
cnxt, server_id)
|
||||
|
||||
@context.request_context
|
||||
def metadata_software_deployments(self, cnxt, server_id):
|
||||
if not server_id:
|
||||
raise ValueError(_('server_id must be specified'))
|
||||
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
|
||||
# sort the configs by config name, to give the list of metadata a
|
||||
# deterministic and controllable order.
|
||||
all_sd_s = sorted(all_sd, key=lambda sd: sd.config.name)
|
||||
result = [api.format_software_config(sd.config) for sd in all_sd_s]
|
||||
return result
|
||||
|
||||
def _push_metadata_software_deployments(self, cnxt, server_id):
|
||||
rs = db_api.resource_get_by_physical_resource_id(cnxt, server_id)
|
||||
if not rs:
|
||||
return
|
||||
deployments = self.metadata_software_deployments(cnxt, server_id)
|
||||
md = rs.rsrc_metadata or {}
|
||||
md['deployments'] = deployments
|
||||
rs.update_and_save({'rsrc_metadata': md})
|
||||
|
||||
metadata_put_url = None
|
||||
for rd in rs.data:
|
||||
if rd.key == 'metadata_put_url':
|
||||
metadata_put_url = rd.value
|
||||
break
|
||||
if metadata_put_url:
|
||||
json_md = jsonutils.dumps(md)
|
||||
requests.put(metadata_put_url, json_md)
|
||||
|
||||
def _refresh_software_deployment(self, cnxt, sd, deploy_signal_id):
|
||||
container, object_name = urlparse.urlparse(
|
||||
deploy_signal_id).path.split('/')[-2:]
|
||||
swift_plugin = cnxt.clients.client_plugin('swift')
|
||||
swift = swift_plugin.client()
|
||||
|
||||
try:
|
||||
headers = swift.head_object(container, object_name)
|
||||
except Exception as ex:
|
||||
# ignore not-found, in case swift is not consistent yet
|
||||
if swift_plugin.is_not_found(ex):
|
||||
LOG.info(_LI('Signal object not found: %(c)s %(o)s') % {
|
||||
'c': container, 'o': object_name})
|
||||
return sd
|
||||
raise ex
|
||||
|
||||
lm = headers.get('last-modified')
|
||||
|
||||
last_modified = swift_plugin.parse_last_modified(lm)
|
||||
prev_last_modified = sd.updated_at
|
||||
|
||||
if prev_last_modified:
|
||||
# assume stored as utc, convert to offset-naive datetime
|
||||
prev_last_modified = prev_last_modified.replace(tzinfo=None)
|
||||
|
||||
if prev_last_modified and (last_modified <= prev_last_modified):
|
||||
return sd
|
||||
|
||||
try:
|
||||
(headers, obj) = swift.get_object(container, object_name)
|
||||
except Exception as ex:
|
||||
# ignore not-found, in case swift is not consistent yet
|
||||
if swift_plugin.is_not_found(ex):
|
||||
LOG.info(_LI(
|
||||
'Signal object not found: %(c)s %(o)s') % {
|
||||
'c': container, 'o': object_name})
|
||||
return sd
|
||||
raise ex
|
||||
if obj:
|
||||
self.signal_software_deployment(
|
||||
cnxt, sd.id, json.loads(obj),
|
||||
timeutils.strtime(last_modified))
|
||||
|
||||
return db_api.software_deployment_get(cnxt, sd.id)
|
||||
return self.software_config.metadata_software_deployments(
|
||||
cnxt, server_id)
|
||||
|
||||
@context.request_context
|
||||
def show_software_deployment(self, cnxt, deployment_id):
|
||||
sd = db_api.software_deployment_get(cnxt, deployment_id)
|
||||
if sd.status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS:
|
||||
c = sd.config.config
|
||||
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
||||
transport = input_values.get('deploy_signal_transport')
|
||||
if transport == 'TEMP_URL_SIGNAL':
|
||||
sd = self._refresh_software_deployment(
|
||||
cnxt, sd, input_values.get('deploy_signal_id'))
|
||||
return api.format_software_deployment(sd)
|
||||
return self.software_config.show_software_deployment(
|
||||
cnxt, deployment_id)
|
||||
|
||||
@context.request_context
|
||||
def create_software_deployment(self, cnxt, server_id, config_id,
|
||||
input_values, action, status,
|
||||
status_reason, stack_user_project_id):
|
||||
|
||||
sd = db_api.software_deployment_create(cnxt, {
|
||||
'config_id': config_id,
|
||||
'server_id': server_id,
|
||||
'input_values': input_values,
|
||||
'tenant': cnxt.tenant_id,
|
||||
'stack_user_project_id': stack_user_project_id,
|
||||
'action': action,
|
||||
'status': status,
|
||||
'status_reason': status_reason})
|
||||
self._push_metadata_software_deployments(cnxt, server_id)
|
||||
return api.format_software_deployment(sd)
|
||||
return self.software_config.create_software_deployment(
|
||||
cnxt, server_id=server_id,
|
||||
config_id=config_id,
|
||||
input_values=input_values,
|
||||
action=action,
|
||||
status=status,
|
||||
status_reason=status_reason,
|
||||
stack_user_project_id=stack_user_project_id)
|
||||
|
||||
@context.request_context
|
||||
def signal_software_deployment(self, cnxt, deployment_id, details,
|
||||
updated_at):
|
||||
|
||||
if not deployment_id:
|
||||
raise ValueError(_('deployment_id must be specified'))
|
||||
|
||||
sd = db_api.software_deployment_get(cnxt, deployment_id)
|
||||
status = sd.status
|
||||
|
||||
if not status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS:
|
||||
# output values are only expected when in an IN_PROGRESS state
|
||||
return
|
||||
|
||||
details = details or {}
|
||||
|
||||
output_status_code = rpc_api.SOFTWARE_DEPLOYMENT_OUTPUT_STATUS_CODE
|
||||
ov = sd.output_values or {}
|
||||
status = None
|
||||
status_reasons = {}
|
||||
status_code = details.get(output_status_code)
|
||||
if status_code and str(status_code) != '0':
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
|
||||
status_reasons[output_status_code] = _(
|
||||
'Deployment exited with non-zero status code: %s'
|
||||
) % details.get(output_status_code)
|
||||
event_reason = 'deployment failed (%s)' % status_code
|
||||
else:
|
||||
event_reason = 'deployment succeeded'
|
||||
|
||||
for output in sd.config.config['outputs'] or []:
|
||||
out_key = output['name']
|
||||
if out_key in details:
|
||||
ov[out_key] = details[out_key]
|
||||
if output.get('error_output', False):
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
|
||||
status_reasons[out_key] = details[out_key]
|
||||
event_reason = 'deployment failed'
|
||||
|
||||
for out_key in rpc_api.SOFTWARE_DEPLOYMENT_OUTPUTS:
|
||||
ov[out_key] = details.get(out_key)
|
||||
|
||||
if status == rpc_api.SOFTWARE_DEPLOYMENT_FAILED:
|
||||
# build a status reason out of all of the values of outputs
|
||||
# flagged as error_output
|
||||
status_reasons = [' : '.join((k, six.text_type(status_reasons[k])))
|
||||
for k in status_reasons]
|
||||
status_reason = ', '.join(status_reasons)
|
||||
else:
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_COMPLETE
|
||||
status_reason = _('Outputs received')
|
||||
|
||||
self.update_software_deployment(
|
||||
cnxt, deployment_id=deployment_id,
|
||||
output_values=ov, status=status, status_reason=status_reason,
|
||||
config_id=None, input_values=None, action=None,
|
||||
return self.software_config.signal_software_deployment(
|
||||
cnxt,
|
||||
deployment_id=deployment_id,
|
||||
details=details,
|
||||
updated_at=updated_at)
|
||||
# Return a string describing the outcome of handling the signal data
|
||||
return event_reason
|
||||
|
||||
@context.request_context
|
||||
def update_software_deployment(self, cnxt, deployment_id, config_id,
|
||||
input_values, output_values, action,
|
||||
status, status_reason, updated_at):
|
||||
update_data = {}
|
||||
if config_id:
|
||||
update_data['config_id'] = config_id
|
||||
if input_values:
|
||||
update_data['input_values'] = input_values
|
||||
if output_values:
|
||||
update_data['output_values'] = output_values
|
||||
if action:
|
||||
update_data['action'] = action
|
||||
if status:
|
||||
update_data['status'] = status
|
||||
if status_reason:
|
||||
update_data['status_reason'] = status_reason
|
||||
if updated_at:
|
||||
update_data['updated_at'] = timeutils.normalize_time(
|
||||
timeutils.parse_isotime(updated_at))
|
||||
else:
|
||||
update_data['updated_at'] = timeutils.utcnow()
|
||||
|
||||
sd = db_api.software_deployment_update(cnxt,
|
||||
deployment_id, update_data)
|
||||
|
||||
# only push metadata if this update resulted in the config_id
|
||||
# changing, since metadata is just a list of configs
|
||||
if config_id:
|
||||
self._push_metadata_software_deployments(cnxt, sd.server_id)
|
||||
|
||||
return api.format_software_deployment(sd)
|
||||
return self.software_config.update_software_deployment(
|
||||
cnxt,
|
||||
deployment_id=deployment_id,
|
||||
config_id=config_id,
|
||||
input_values=input_values,
|
||||
output_values=output_values,
|
||||
action=action,
|
||||
status=status,
|
||||
status_reason=status_reason,
|
||||
updated_at=updated_at)
|
||||
|
||||
@context.request_context
|
||||
def delete_software_deployment(self, cnxt, deployment_id):
|
||||
db_api.software_deployment_delete(cnxt, deployment_id)
|
||||
return self.software_config.delete_software_deployment(
|
||||
cnxt, deployment_id)
|
||||
|
||||
@context.request_context
|
||||
def list_services(self, cnxt):
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
import requests
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from heat.common.i18n import _
|
||||
from heat.common.i18n import _LI
|
||||
from heat.db import api as db_api
|
||||
from heat.engine import api
|
||||
from heat.openstack.common import service
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SoftwareConfigService(service.Service):
|
||||
|
||||
def show_software_config(self, cnxt, config_id):
|
||||
sc = db_api.software_config_get(cnxt, config_id)
|
||||
return api.format_software_config(sc)
|
||||
|
||||
def create_software_config(self, cnxt, group, name, config,
|
||||
inputs, outputs, options):
|
||||
|
||||
sc = db_api.software_config_create(cnxt, {
|
||||
'group': group,
|
||||
'name': name,
|
||||
'config': {
|
||||
'inputs': inputs,
|
||||
'outputs': outputs,
|
||||
'options': options,
|
||||
'config': config
|
||||
},
|
||||
'tenant': cnxt.tenant_id})
|
||||
return api.format_software_config(sc)
|
||||
|
||||
def delete_software_config(self, cnxt, config_id):
|
||||
db_api.software_config_delete(cnxt, config_id)
|
||||
|
||||
def list_software_deployments(self, cnxt, server_id):
|
||||
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
|
||||
result = [api.format_software_deployment(sd) for sd in all_sd]
|
||||
return result
|
||||
|
||||
def metadata_software_deployments(self, cnxt, server_id):
|
||||
if not server_id:
|
||||
raise ValueError(_('server_id must be specified'))
|
||||
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
|
||||
# sort the configs by config name, to give the list of metadata a
|
||||
# deterministic and controllable order.
|
||||
all_sd_s = sorted(all_sd, key=lambda sd: sd.config.name)
|
||||
result = [api.format_software_config(sd.config) for sd in all_sd_s]
|
||||
return result
|
||||
|
||||
def _push_metadata_software_deployments(self, cnxt, server_id):
|
||||
rs = db_api.resource_get_by_physical_resource_id(cnxt, server_id)
|
||||
if not rs:
|
||||
return
|
||||
deployments = self.metadata_software_deployments(cnxt, server_id)
|
||||
md = rs.rsrc_metadata or {}
|
||||
md['deployments'] = deployments
|
||||
rs.update_and_save({'rsrc_metadata': md})
|
||||
|
||||
metadata_put_url = None
|
||||
for rd in rs.data:
|
||||
if rd.key == 'metadata_put_url':
|
||||
metadata_put_url = rd.value
|
||||
break
|
||||
if metadata_put_url:
|
||||
json_md = jsonutils.dumps(md)
|
||||
requests.put(metadata_put_url, json_md)
|
||||
|
||||
def _refresh_software_deployment(self, cnxt, sd, deploy_signal_id):
|
||||
container, object_name = urlparse.urlparse(
|
||||
deploy_signal_id).path.split('/')[-2:]
|
||||
swift_plugin = cnxt.clients.client_plugin('swift')
|
||||
swift = swift_plugin.client()
|
||||
|
||||
try:
|
||||
headers = swift.head_object(container, object_name)
|
||||
except Exception as ex:
|
||||
# ignore not-found, in case swift is not consistent yet
|
||||
if swift_plugin.is_not_found(ex):
|
||||
LOG.info(_LI('Signal object not found: %(c)s %(o)s') % {
|
||||
'c': container, 'o': object_name})
|
||||
return sd
|
||||
raise ex
|
||||
|
||||
lm = headers.get('last-modified')
|
||||
|
||||
last_modified = swift_plugin.parse_last_modified(lm)
|
||||
prev_last_modified = sd.updated_at
|
||||
|
||||
if prev_last_modified:
|
||||
# assume stored as utc, convert to offset-naive datetime
|
||||
prev_last_modified = prev_last_modified.replace(tzinfo=None)
|
||||
|
||||
if prev_last_modified and (last_modified <= prev_last_modified):
|
||||
return sd
|
||||
|
||||
try:
|
||||
(headers, obj) = swift.get_object(container, object_name)
|
||||
except Exception as ex:
|
||||
# ignore not-found, in case swift is not consistent yet
|
||||
if swift_plugin.is_not_found(ex):
|
||||
LOG.info(_LI(
|
||||
'Signal object not found: %(c)s %(o)s') % {
|
||||
'c': container, 'o': object_name})
|
||||
return sd
|
||||
raise ex
|
||||
if obj:
|
||||
self.signal_software_deployment(
|
||||
cnxt, sd.id, json.loads(obj),
|
||||
timeutils.strtime(last_modified))
|
||||
|
||||
return db_api.software_deployment_get(cnxt, sd.id)
|
||||
|
||||
def show_software_deployment(self, cnxt, deployment_id):
|
||||
sd = db_api.software_deployment_get(cnxt, deployment_id)
|
||||
if sd.status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS:
|
||||
c = sd.config.config
|
||||
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
||||
transport = input_values.get('deploy_signal_transport')
|
||||
if transport == 'TEMP_URL_SIGNAL':
|
||||
sd = self._refresh_software_deployment(
|
||||
cnxt, sd, input_values.get('deploy_signal_id'))
|
||||
return api.format_software_deployment(sd)
|
||||
|
||||
def create_software_deployment(self, cnxt, server_id, config_id,
|
||||
input_values, action, status,
|
||||
status_reason, stack_user_project_id):
|
||||
|
||||
sd = db_api.software_deployment_create(cnxt, {
|
||||
'config_id': config_id,
|
||||
'server_id': server_id,
|
||||
'input_values': input_values,
|
||||
'tenant': cnxt.tenant_id,
|
||||
'stack_user_project_id': stack_user_project_id,
|
||||
'action': action,
|
||||
'status': status,
|
||||
'status_reason': status_reason})
|
||||
self._push_metadata_software_deployments(cnxt, server_id)
|
||||
return api.format_software_deployment(sd)
|
||||
|
||||
def signal_software_deployment(self, cnxt, deployment_id, details,
|
||||
updated_at):
|
||||
|
||||
if not deployment_id:
|
||||
raise ValueError(_('deployment_id must be specified'))
|
||||
|
||||
sd = db_api.software_deployment_get(cnxt, deployment_id)
|
||||
status = sd.status
|
||||
|
||||
if not status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS:
|
||||
# output values are only expected when in an IN_PROGRESS state
|
||||
return
|
||||
|
||||
details = details or {}
|
||||
|
||||
output_status_code = rpc_api.SOFTWARE_DEPLOYMENT_OUTPUT_STATUS_CODE
|
||||
ov = sd.output_values or {}
|
||||
status = None
|
||||
status_reasons = {}
|
||||
status_code = details.get(output_status_code)
|
||||
if status_code and str(status_code) != '0':
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
|
||||
status_reasons[output_status_code] = _(
|
||||
'Deployment exited with non-zero status code: %s'
|
||||
) % details.get(output_status_code)
|
||||
event_reason = 'deployment failed (%s)' % status_code
|
||||
else:
|
||||
event_reason = 'deployment succeeded'
|
||||
|
||||
for output in sd.config.config['outputs'] or []:
|
||||
out_key = output['name']
|
||||
if out_key in details:
|
||||
ov[out_key] = details[out_key]
|
||||
if output.get('error_output', False):
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED
|
||||
status_reasons[out_key] = details[out_key]
|
||||
event_reason = 'deployment failed'
|
||||
|
||||
for out_key in rpc_api.SOFTWARE_DEPLOYMENT_OUTPUTS:
|
||||
ov[out_key] = details.get(out_key)
|
||||
|
||||
if status == rpc_api.SOFTWARE_DEPLOYMENT_FAILED:
|
||||
# build a status reason out of all of the values of outputs
|
||||
# flagged as error_output
|
||||
status_reasons = [' : '.join((k, six.text_type(status_reasons[k])))
|
||||
for k in status_reasons]
|
||||
status_reason = ', '.join(status_reasons)
|
||||
else:
|
||||
status = rpc_api.SOFTWARE_DEPLOYMENT_COMPLETE
|
||||
status_reason = _('Outputs received')
|
||||
|
||||
self.update_software_deployment(
|
||||
cnxt, deployment_id=deployment_id,
|
||||
output_values=ov, status=status, status_reason=status_reason,
|
||||
config_id=None, input_values=None, action=None,
|
||||
updated_at=updated_at)
|
||||
# Return a string describing the outcome of handling the signal data
|
||||
return event_reason
|
||||
|
||||
def update_software_deployment(self, cnxt, deployment_id, config_id,
|
||||
input_values, output_values, action,
|
||||
status, status_reason, updated_at):
|
||||
update_data = {}
|
||||
if config_id:
|
||||
update_data['config_id'] = config_id
|
||||
if input_values:
|
||||
update_data['input_values'] = input_values
|
||||
if output_values:
|
||||
update_data['output_values'] = output_values
|
||||
if action:
|
||||
update_data['action'] = action
|
||||
if status:
|
||||
update_data['status'] = status
|
||||
if status_reason:
|
||||
update_data['status_reason'] = status_reason
|
||||
if updated_at:
|
||||
update_data['updated_at'] = timeutils.normalize_time(
|
||||
timeutils.parse_isotime(updated_at))
|
||||
else:
|
||||
update_data['updated_at'] = timeutils.utcnow()
|
||||
|
||||
sd = db_api.software_deployment_update(cnxt,
|
||||
deployment_id, update_data)
|
||||
|
||||
# only push metadata if this update resulted in the config_id
|
||||
# changing, since metadata is just a list of configs
|
||||
if config_id:
|
||||
self._push_metadata_software_deployments(cnxt, sd.server_id)
|
||||
|
||||
return api.format_software_deployment(sd)
|
||||
|
||||
def delete_software_deployment(self, cnxt, deployment_id):
|
||||
db_api.software_deployment_delete(cnxt, deployment_id)
|
|
@ -42,6 +42,7 @@ from heat.engine import properties
|
|||
from heat.engine import resource as res
|
||||
from heat.engine.resources.aws import instance as instances
|
||||
from heat.engine import service
|
||||
from heat.engine import service_software_config
|
||||
from heat.engine import service_stack_watch
|
||||
from heat.engine import stack as parser
|
||||
from heat.engine import stack_lock
|
||||
|
@ -3636,7 +3637,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
deployment,
|
||||
self.engine.show_software_deployment(self.ctx, deployment_id))
|
||||
|
||||
@mock.patch.object(service.EngineService,
|
||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||
'_push_metadata_software_deployments')
|
||||
def test_signal_software_deployment(self, pmsd):
|
||||
self.assertRaises(ValueError,
|
||||
|
@ -3780,7 +3781,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
self.assertEqual(deployment_id, deployment['id'])
|
||||
self.assertEqual(kwargs['input_values'], deployment['input_values'])
|
||||
|
||||
@mock.patch.object(service.EngineService, '_refresh_software_deployment')
|
||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||
'_refresh_software_deployment')
|
||||
def test_show_software_deployment_refresh(
|
||||
self, _refresh_software_deployment):
|
||||
temp_url = ('http://192.0.2.1/v1/AUTH_a/b/c'
|
||||
|
@ -3814,13 +3816,14 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
|
||||
server_id = str(uuid.uuid4())
|
||||
self.m.StubOutWithMock(
|
||||
self.engine, '_push_metadata_software_deployments')
|
||||
self.engine.software_config,
|
||||
'_push_metadata_software_deployments')
|
||||
|
||||
# push on create
|
||||
self.engine._push_metadata_software_deployments(
|
||||
self.engine.software_config._push_metadata_software_deployments(
|
||||
self.ctx, server_id).AndReturn(None)
|
||||
# push on update with new config_id
|
||||
self.engine._push_metadata_software_deployments(
|
||||
self.engine.software_config._push_metadata_software_deployments(
|
||||
self.ctx, server_id).AndReturn(None)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -3846,9 +3849,10 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
|
||||
server_id = str(uuid.uuid4())
|
||||
self.m.StubOutWithMock(
|
||||
self.engine, '_push_metadata_software_deployments')
|
||||
self.engine.software_config,
|
||||
'_push_metadata_software_deployments')
|
||||
# push on create
|
||||
self.engine._push_metadata_software_deployments(
|
||||
self.engine.software_config._push_metadata_software_deployments(
|
||||
self.ctx, server_id).AndReturn(None)
|
||||
# _push_metadata_software_deployments should not be called
|
||||
# on update because config_id isn't being updated
|
||||
|
@ -3916,7 +3920,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
deployment_ids = [x['id'] for x in deployments]
|
||||
self.assertNotIn(deployment_id, deployment_ids)
|
||||
|
||||
@mock.patch.object(service.EngineService, 'metadata_software_deployments')
|
||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||
'metadata_software_deployments')
|
||||
@mock.patch.object(service.db_api, 'resource_get_by_physical_resource_id')
|
||||
@mock.patch.object(service.requests, 'put')
|
||||
def test_push_metadata_software_deployments(self, put, res_get, md_sd):
|
||||
|
@ -3933,12 +3938,14 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
'deployments': {'deploy': 'this'}
|
||||
}
|
||||
|
||||
self.engine._push_metadata_software_deployments(self.ctx, '1234')
|
||||
self.engine.software_config._push_metadata_software_deployments(
|
||||
self.ctx, '1234')
|
||||
rs.update_and_save.assert_called_once_with(
|
||||
{'rsrc_metadata': result_metadata})
|
||||
put.side_effect = Exception('Unexpected requests.put')
|
||||
|
||||
@mock.patch.object(service.EngineService, 'metadata_software_deployments')
|
||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||
'metadata_software_deployments')
|
||||
@mock.patch.object(service.db_api, 'resource_get_by_physical_resource_id')
|
||||
@mock.patch.object(service.requests, 'put')
|
||||
def test_push_metadata_software_deployments_temp_url(
|
||||
|
@ -3959,14 +3966,15 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
'deployments': {'deploy': 'this'}
|
||||
}
|
||||
|
||||
self.engine._push_metadata_software_deployments(self.ctx, '1234')
|
||||
self.engine.software_config._push_metadata_software_deployments(
|
||||
self.ctx, '1234')
|
||||
rs.update_and_save.assert_called_once_with(
|
||||
{'rsrc_metadata': result_metadata})
|
||||
|
||||
put.assert_called_once_with(
|
||||
'http://192.168.2.2/foo/bar', jsonutils.dumps(result_metadata))
|
||||
|
||||
@mock.patch.object(service.EngineService,
|
||||
@mock.patch.object(service_software_config.SoftwareConfigService,
|
||||
'signal_software_deployment')
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
def test_refresh_software_deployment(self, scc, ssd):
|
||||
|
@ -4017,7 +4025,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
|
||||
self.assertEqual(
|
||||
sd,
|
||||
self.engine._refresh_software_deployment(self.ctx, sd, temp_url))
|
||||
self.engine.software_config._refresh_software_deployment(
|
||||
self.ctx, sd, temp_url))
|
||||
sc.head_object.assert_called_once_with(container, object_name)
|
||||
# no call to get_object or signal_last_modified
|
||||
self.assertEqual([], sc.get_object.mock_calls)
|
||||
|
@ -4026,16 +4035,20 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
# poll with other error
|
||||
sc.head_object.side_effect = swift_exc.ClientException(
|
||||
'Ouch', http_status=409)
|
||||
self.assertRaises(swift_exc.ClientException,
|
||||
self.engine._refresh_software_deployment,
|
||||
self.ctx, sd, temp_url)
|
||||
self.assertRaises(
|
||||
swift_exc.ClientException,
|
||||
self.engine.software_config._refresh_software_deployment,
|
||||
self.ctx,
|
||||
sd,
|
||||
temp_url)
|
||||
# no call to get_object or signal_last_modified
|
||||
self.assertEqual([], sc.get_object.mock_calls)
|
||||
self.assertEqual([], ssd.mock_calls)
|
||||
sc.head_object.side_effect = None
|
||||
|
||||
# first poll populates data signal_last_modified
|
||||
self.engine._refresh_software_deployment(self.ctx, sd, temp_url)
|
||||
self.engine.software_config._refresh_software_deployment(
|
||||
self.ctx, sd, temp_url)
|
||||
sc.head_object.assert_called_with(container, object_name)
|
||||
sc.get_object.assert_called_once_with(container, object_name)
|
||||
# signal_software_deployment called with signal
|
||||
|
@ -4047,7 +4060,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
self.ctx, deployment_id, {'updated_at': then})
|
||||
sd = db_api.software_deployment_get(self.ctx, deployment_id)
|
||||
self.assertEqual(then, sd.updated_at)
|
||||
self.engine._refresh_software_deployment(self.ctx, sd, temp_url)
|
||||
self.engine.software_config._refresh_software_deployment(
|
||||
self.ctx, sd, temp_url)
|
||||
sc.get_object.assert_called_once_with(container, object_name)
|
||||
# signal_software_deployment has not been called again
|
||||
ssd.assert_called_once_with(self.ctx, deployment_id, {"foo": "bar"},
|
||||
|
@ -4057,7 +4071,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
headers['last-modified'] = last_modified_2
|
||||
sc.head_object.return_value = headers
|
||||
sc.get_object.return_value = (headers, '{"bar": "baz"}')
|
||||
self.engine._refresh_software_deployment(self.ctx, sd, temp_url)
|
||||
self.engine.software_config._refresh_software_deployment(
|
||||
self.ctx, sd, temp_url)
|
||||
|
||||
# two calls to signal_software_deployment, for then and now
|
||||
self.assertEqual(2, len(ssd.mock_calls))
|
||||
|
@ -4068,7 +4083,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
|
|||
db_api.software_deployment_update(
|
||||
self.ctx, deployment_id, {'updated_at': now})
|
||||
sd = db_api.software_deployment_get(self.ctx, deployment_id)
|
||||
self.engine._refresh_software_deployment(self.ctx, sd, temp_url)
|
||||
self.engine.software_config._refresh_software_deployment(
|
||||
self.ctx, sd, temp_url)
|
||||
self.assertEqual(2, len(ssd.mock_calls))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue