Add OS::Swift::Signal resource
blueprint swiftsignal-resource Change-Id: I5ba523210aa9aefbf46eeaa0d95293608a820f95
This commit is contained in:
parent
f388b2e2a8
commit
4285dcc2de
319
heat/engine/resources/swiftsignal.py
Normal file
319
heat/engine/resources/swiftsignal.py
Normal file
@ -0,0 +1,319 @@
|
||||
#
|
||||
# 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
|
||||
import urlparse
|
||||
|
||||
from swiftclient import client as swiftclient_client
|
||||
|
||||
from heat.common import exception
|
||||
from heat.engine import attributes
|
||||
from heat.engine.clients.os import swift
|
||||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine import resource
|
||||
from heat.engine import scheduler
|
||||
from heat.openstack.common.gettextutils import _
|
||||
from heat.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SwiftSignalFailure(exception.Error):
|
||||
def __init__(self, wait_cond):
|
||||
reasons = wait_cond.get_status_reason(wait_cond.STATUS_FAILURE)
|
||||
super(SwiftSignalFailure, self).__init__(';'.join(reasons))
|
||||
|
||||
|
||||
class SwiftSignalTimeout(exception.Error):
|
||||
def __init__(self, wait_cond):
|
||||
reasons = wait_cond.get_status_reason(wait_cond.STATUS_SUCCESS)
|
||||
vals = {'len': len(reasons),
|
||||
'count': wait_cond.properties[wait_cond.COUNT]}
|
||||
if reasons:
|
||||
vals['reasons'] = ';'.join(reasons)
|
||||
message = (_('%(len)d of %(count)d received - %(reasons)s') % vals)
|
||||
else:
|
||||
message = (_('%(len)d of %(count)d received') % vals)
|
||||
super(SwiftSignalTimeout, self).__init__(message)
|
||||
|
||||
|
||||
class SwiftSignalHandle(resource.Resource):
|
||||
|
||||
properties_schema = {}
|
||||
|
||||
ATTRIBUTES = (
|
||||
TOKEN,
|
||||
ENDPOINT,
|
||||
CURL_CLI,
|
||||
) = (
|
||||
'token',
|
||||
'endpoint',
|
||||
'curl_cli',
|
||||
)
|
||||
|
||||
attributes_schema = {
|
||||
TOKEN: attributes.Schema(
|
||||
_('Tokens are not needed for Swift TempURLs. This attribute is '
|
||||
'being kept for compatibility with the '
|
||||
'OS::Heat::WaitConditionHandle resource'),
|
||||
cache_mode=attributes.Schema.CACHE_NONE
|
||||
),
|
||||
ENDPOINT: attributes.Schema(
|
||||
_('Endpoint/url which can be used for signalling handle'),
|
||||
cache_mode=attributes.Schema.CACHE_NONE
|
||||
),
|
||||
CURL_CLI: attributes.Schema(
|
||||
_('Convenience attribute, provides curl CLI command '
|
||||
'prefix, which can be used for signalling handle completion or '
|
||||
'failure. You can signal success by adding '
|
||||
'--data-binary \'{"status": "SUCCESS"}\' '
|
||||
', or signal failure by adding '
|
||||
'--data-binary \'{"status": "FAILURE"}\''),
|
||||
cache_mode=attributes.Schema.CACHE_NONE
|
||||
),
|
||||
}
|
||||
|
||||
def handle_create(self):
|
||||
sc = self.client_plugin('swift')
|
||||
url = sc.get_signal_url(self.stack.id, self.physical_resource_name())
|
||||
self.data_set('endpoint', url)
|
||||
self.resource_id_set(url)
|
||||
|
||||
def update(self, after, before=None, prev_resource=None):
|
||||
raise resource.UpdateReplace(self.name)
|
||||
|
||||
def _resolve_attribute(self, key):
|
||||
if self.resource_id:
|
||||
if key == self.TOKEN:
|
||||
return '' # HeatWaitConditionHandle compatibility
|
||||
elif key == self.ENDPOINT:
|
||||
return self.data().get('endpoint')
|
||||
elif key == self.CURL_CLI:
|
||||
return ('curl -i -X PUT \'%s\'' % self.data().get('endpoint'))
|
||||
|
||||
|
||||
class SwiftSignal(resource.Resource):
|
||||
|
||||
PROPERTIES = (HANDLE, TIMEOUT, COUNT,) = ('handle', 'timeout', 'count',)
|
||||
|
||||
properties_schema = {
|
||||
HANDLE: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
required=True,
|
||||
description=_('URL of TempURL where resource will signal '
|
||||
'completion and optionally upload data.')
|
||||
),
|
||||
TIMEOUT: properties.Schema(
|
||||
properties.Schema.NUMBER,
|
||||
description=_('The maximum number of seconds to wait for the '
|
||||
'resource to signal completion. Once the timeout '
|
||||
'is reached, creation of the signal resource will '
|
||||
'fail.'),
|
||||
required=True,
|
||||
constraints=[
|
||||
constraints.Range(1, 43200),
|
||||
]
|
||||
),
|
||||
COUNT: properties.Schema(
|
||||
properties.Schema.NUMBER,
|
||||
description=_('The number of success signals that must be '
|
||||
'received before the stack creation process '
|
||||
'continues.'),
|
||||
default=1,
|
||||
constraints=[
|
||||
constraints.Range(1, 1000),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
ATTRIBUTES = (DATA) = 'data'
|
||||
|
||||
attributes_schema = {
|
||||
DATA: attributes.Schema(
|
||||
_('JSON data that was uploaded via the SwiftSignalHandle.')
|
||||
)
|
||||
}
|
||||
|
||||
WAIT_STATUSES = (
|
||||
STATUS_FAILURE,
|
||||
STATUS_SUCCESS,
|
||||
) = (
|
||||
'FAILURE',
|
||||
'SUCCESS',
|
||||
)
|
||||
|
||||
METADATA_KEYS = (
|
||||
DATA, REASON, STATUS, UNIQUE_ID
|
||||
) = (
|
||||
'data', 'reason', 'status', 'id'
|
||||
)
|
||||
|
||||
def __init__(self, name, json_snippet, stack):
|
||||
super(SwiftSignal, self).__init__(name, json_snippet, stack)
|
||||
self._obj_name = None
|
||||
self._url = None
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
if not self._url:
|
||||
self._url = urlparse.urlparse(self.properties[self.HANDLE])
|
||||
return self._url
|
||||
|
||||
@property
|
||||
def obj_name(self):
|
||||
if not self._obj_name:
|
||||
self._obj_name = self.url.path.split('/')[4]
|
||||
return self._obj_name
|
||||
|
||||
def _validate_handle_url(self):
|
||||
parts = self.url.path.split('/')
|
||||
msg = _('"%(url)s" is not a valid SwiftSignalHandle. The %(part)s '
|
||||
'is invalid')
|
||||
sc = self.client_plugin('swift')
|
||||
if not sc.is_valid_temp_url_path(self.url.path):
|
||||
raise ValueError(msg % {'url': self.url.path,
|
||||
'part': 'Swift TempURL path'})
|
||||
if not parts[2].endswith(self.context.tenant_id):
|
||||
raise ValueError(msg % {'url': self.url.path,
|
||||
'part': 'tenant'})
|
||||
if not parts[3] == self.stack.id:
|
||||
raise ValueError(msg % {'url': self.url.path,
|
||||
'part': 'container name'})
|
||||
|
||||
def handle_create(self):
|
||||
self._validate_handle_url()
|
||||
runner = scheduler.TaskRunner(self._wait)
|
||||
runner.start(timeout=float(self.properties.get(self.TIMEOUT)))
|
||||
return runner
|
||||
|
||||
def _wait(self):
|
||||
while True:
|
||||
try:
|
||||
yield
|
||||
except scheduler.Timeout:
|
||||
count = self.properties.get(self.COUNT)
|
||||
raise SwiftSignalTimeout(self)
|
||||
|
||||
count = self.properties.get(self.COUNT)
|
||||
statuses = self.get_status()
|
||||
if not statuses:
|
||||
continue
|
||||
|
||||
for status in statuses:
|
||||
if status == self.STATUS_FAILURE:
|
||||
failure = SwiftSignalFailure(self)
|
||||
LOG.info(_('%(name)s Failed (%(failure)s)')
|
||||
% {'name': str(self), 'failure': str(failure)})
|
||||
raise failure
|
||||
elif status != self.STATUS_SUCCESS:
|
||||
raise exception.Error(_("Unknown status: %s") % status)
|
||||
|
||||
if len(statuses) >= count:
|
||||
LOG.info(_("%s Succeeded") % str(self))
|
||||
return
|
||||
|
||||
def get_signals(self):
|
||||
try:
|
||||
container = self.swift().get_container(self.stack.id)
|
||||
except swiftclient_client.ClientException as exc:
|
||||
if exc.http_status == 404: # Swift container was deleted by user
|
||||
return None
|
||||
raise exc
|
||||
|
||||
index = container[1]
|
||||
if not index: # Swift objects were deleted by user
|
||||
return None
|
||||
|
||||
# Remove objects in that are for other handle resources, since
|
||||
# multiple SwiftSignalHandle resources in the same stack share
|
||||
# a container
|
||||
filtered = [obj for obj in index if self.obj_name in obj['name']]
|
||||
|
||||
# Fetch objects from Swift and filter results
|
||||
obj_bodies = []
|
||||
for obj in filtered:
|
||||
try:
|
||||
signal = self.swift().get_object(self.stack.id, obj['name'])
|
||||
except swiftclient_client.ClientException as exc:
|
||||
if exc.http_status == 404: # Swift object disappeared
|
||||
continue
|
||||
raise exc
|
||||
|
||||
body = signal[1]
|
||||
if body == swift.IN_PROGRESS: # Ignore the initial object
|
||||
continue
|
||||
if body == "":
|
||||
obj_bodies.append({})
|
||||
continue
|
||||
try:
|
||||
obj_bodies.append(json.loads(body))
|
||||
except ValueError:
|
||||
raise exception.Error(_("Failed to parse JSON data: %s") %
|
||||
body)
|
||||
|
||||
# Set default values on each signal
|
||||
signals = []
|
||||
signal_num = 1
|
||||
for signal in obj_bodies:
|
||||
|
||||
# Remove previous signals with the same ID
|
||||
id = self.UNIQUE_ID
|
||||
ids = [s.get(id) for s in signals if id in s]
|
||||
if ids and id in signal and ids.count(signal[id]) > 0:
|
||||
[signals.remove(s) for s in signals if s.get(id) == signal[id]]
|
||||
|
||||
# Make sure all fields are set, since all are optional
|
||||
signal.setdefault(self.DATA, None)
|
||||
unique_id = signal.setdefault(self.UNIQUE_ID, signal_num)
|
||||
reason = 'Signal %s recieved' % unique_id
|
||||
signal.setdefault(self.REASON, reason)
|
||||
signal.setdefault(self.STATUS, self.STATUS_SUCCESS)
|
||||
|
||||
signals.append(signal)
|
||||
signal_num += 1
|
||||
|
||||
return signals
|
||||
|
||||
def get_status(self):
|
||||
return [s[self.STATUS] for s in self.get_signals()]
|
||||
|
||||
def get_status_reason(self, status):
|
||||
return [s[self.REASON]
|
||||
for s in self.get_signals()
|
||||
if s[self.STATUS] == status]
|
||||
|
||||
def get_data(self):
|
||||
signals = self.get_signals()
|
||||
if not signals:
|
||||
return None
|
||||
data = {}
|
||||
for signal in signals:
|
||||
data[signal[self.UNIQUE_ID]] = signal[self.DATA]
|
||||
return data
|
||||
|
||||
def check_create_complete(self, runner):
|
||||
return runner.step()
|
||||
|
||||
def _resolve_attribute(self, key):
|
||||
if key == self.DATA:
|
||||
return unicode(json.dumps(self.get_data()))
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
return {'OS::Heat::SwiftSignal': SwiftSignal,
|
||||
'OS::Heat::SwiftSignalHandle': SwiftSignalHandle}
|
||||
|
||||
|
||||
def available_resource_mapping():
|
||||
return resource_mapping()
|
756
heat/tests/test_swiftsignal.py
Normal file
756
heat/tests/test_swiftsignal.py
Normal file
@ -0,0 +1,756 @@
|
||||
#
|
||||
# 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 copy
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
import six
|
||||
from swiftclient import client as swiftclient_client
|
||||
from testtools.matchers import MatchesRegex
|
||||
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients.os import swift
|
||||
from heat.engine import environment
|
||||
from heat.engine import resource
|
||||
from heat.engine import rsrc_defn
|
||||
from heat.engine import scheduler
|
||||
from heat.engine import stack
|
||||
from heat.tests.common import HeatTestCase
|
||||
from heat.tests import utils
|
||||
|
||||
|
||||
swiftsignal_template = '''
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
resources:
|
||||
test_wait_condition:
|
||||
type: "OS::Heat::SwiftSignal"
|
||||
properties:
|
||||
handle: { get_resource: test_wait_condition_handle }
|
||||
timeout: 1
|
||||
count: 2
|
||||
|
||||
test_wait_condition_handle:
|
||||
type: "OS::Heat::SwiftSignalHandle"
|
||||
'''
|
||||
|
||||
swiftsignalhandle_template = '''
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
resources:
|
||||
test_wait_condition_handle:
|
||||
type: "OS::Heat::SwiftSignalHandle"
|
||||
'''
|
||||
|
||||
container_header = {
|
||||
'content-length': '2',
|
||||
'x-container-object-count': '0',
|
||||
'accept-ranges': 'bytes',
|
||||
'date': 'Fri, 25 Jul 2014 16:02:03 GMT',
|
||||
'x-timestamp': '1405019787.66969',
|
||||
'x-trans-id': 'tx6651b005324341f685e71-0053d27f7bdfw1',
|
||||
'x-container-bytes-used': '0',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
'x-versions-location': 'test'
|
||||
}
|
||||
|
||||
obj_header = {
|
||||
'content-length': '5',
|
||||
'accept-ranges': 'bytes',
|
||||
'last-modified': 'Fri, 25 Jul 2014 16:05:26 GMT',
|
||||
'etag': '5a105e8b9d40e1329780d62ea2265d8a',
|
||||
'x-timestamp': '1406304325.40094',
|
||||
'x-trans-id': 'tx2f40ff2b4daa4015917fc-0053d28045dfw1',
|
||||
'date': 'Fri, 25 Jul 2014 16:05:25 GMT',
|
||||
'content-type': 'application/octet-stream'
|
||||
}
|
||||
|
||||
|
||||
def create_stack(template, stack_id=None):
|
||||
tmpl = template_format.parse(template)
|
||||
template = stack.Template(tmpl)
|
||||
ctx = utils.dummy_context(tenant_id='test_tenant')
|
||||
st = stack.Stack(ctx, 'test_st', template,
|
||||
environment.Environment(),
|
||||
disable_rollback=True)
|
||||
|
||||
# Stub out the stack ID so we have a known value
|
||||
if stack_id is None:
|
||||
stack_id = str(uuid.uuid4())
|
||||
with utils.UUIDStub(stack_id):
|
||||
st.store()
|
||||
st.id = stack_id
|
||||
|
||||
return st
|
||||
|
||||
|
||||
def cont_index(obj_name, num_version_hist):
|
||||
objects = [{'bytes': 11,
|
||||
'last_modified': '2014-07-03T19:42:03.281640',
|
||||
'hash': '9214b4e4460fcdb9f3a369941400e71e',
|
||||
'name': "02b" + obj_name + '/1404416326.51383',
|
||||
'content_type': 'application/octet-stream'}] * num_version_hist
|
||||
objects.append({'bytes': 8,
|
||||
'last_modified': '2014-07-03T19:42:03.849870',
|
||||
'hash': '9ab7c0738852d7dd6a2dc0b261edc300',
|
||||
'name': obj_name,
|
||||
'content_type': 'application/x-www-form-urlencoded'})
|
||||
return (container_header, objects)
|
||||
|
||||
|
||||
class SwiftSignalHandleTest(HeatTestCase):
|
||||
def setUp(self):
|
||||
super(SwiftSignalHandleTest, self).setUp()
|
||||
utils.setup_dummy_db()
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_create(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignalhandle_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': "1234"
|
||||
}
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
mock_swift_object.get_object.return_value = (obj_header, '{"id": "1"}')
|
||||
|
||||
st.create()
|
||||
handle = st.resources['test_wait_condition_handle']
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
regexp = ("http://fake-host.com:8080/v1/AUTH_test_tenant/%s/test_st-"
|
||||
"test_wait_condition_handle-abcdefghijkl"
|
||||
"\?temp_url_sig=[0-9a-f]{40}&temp_url_expires=[0-9]{10}"
|
||||
% st.id)
|
||||
res_id = st.resources['test_wait_condition_handle'].resource_id
|
||||
self.assertThat(res_id, MatchesRegex(regexp))
|
||||
|
||||
# Since the account key is mocked out above
|
||||
self.assertFalse(mock_swift_object.post_account.called)
|
||||
|
||||
header = {'x-versions-location': st.id}
|
||||
self.assertEqual({'headers': header},
|
||||
mock_swift_object.put_container.call_args[1])
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
def test_handle_update(self, mock_swift):
|
||||
st = create_stack(swiftsignalhandle_template)
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.head_account.return_value = {}
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
|
||||
st.create()
|
||||
|
||||
handle = st['test_wait_condition_handle']
|
||||
uprops = copy.copy(handle.properties.data)
|
||||
uprops['count'] = '5'
|
||||
update_snippet = rsrc_defn.ResourceDefinition(handle.name,
|
||||
handle.type(),
|
||||
uprops)
|
||||
|
||||
updater = scheduler.TaskRunner(handle.update, update_snippet)
|
||||
self.assertRaises(resource.UpdateReplace, updater)
|
||||
|
||||
|
||||
class SwiftSignalTest(HeatTestCase):
|
||||
def setUp(self):
|
||||
super(SwiftSignalTest, self).setUp()
|
||||
utils.setup_dummy_db()
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_create(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
mock_swift_object.get_object.return_value = (obj_header, '')
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, 'get_signal_url')
|
||||
def test_validate_handle_url_bad_tempurl(self, mock_handle_url):
|
||||
mock_handle_url.return_value = (
|
||||
"http://fake-host.com:8080/v1/my-container/"
|
||||
"test_st-test_wait_condition_handle?temp_url_sig="
|
||||
"12d8f9f2c923fbeb555041d4ed63d83de6768e95&"
|
||||
"temp_url_expires=1404762741")
|
||||
st = create_stack(swiftsignal_template)
|
||||
|
||||
st.create()
|
||||
self.assertIn('not a valid SwiftSignalHandle. The Swift TempURL path',
|
||||
six.text_type(st.status_reason))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, 'get_signal_url')
|
||||
def test_validate_handle_url_bad_container_name(self, mock_handle_url):
|
||||
mock_handle_url.return_value = (
|
||||
"http://fake-host.com:8080/v1/AUTH_test_tenant/my-container/"
|
||||
"test_st-test_wait_condition_handle?temp_url_sig="
|
||||
"12d8f9f2c923fbeb555041d4ed63d83de6768e95&"
|
||||
"temp_url_expires=1404762741")
|
||||
st = create_stack(swiftsignal_template)
|
||||
|
||||
st.create()
|
||||
self.assertIn('not a valid SwiftSignalHandle. The container name',
|
||||
six.text_type(st.status_reason))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, 'get_signal_url')
|
||||
def test_validate_handle_url_bad_tenant(self, mock_handle_url):
|
||||
stack_id = '1234'
|
||||
mock_handle_url.return_value = (
|
||||
"http://fake-host.com:8080/v1/AUTH_foo/%s/"
|
||||
"test_st-test_wait_condition_handle?temp_url_sig="
|
||||
"12d8f9f2c923fbeb555041d4ed63d83de6768e95&"
|
||||
"temp_url_expires=1404762741" % stack_id)
|
||||
st = create_stack(swiftsignal_template, stack_id=stack_id)
|
||||
|
||||
st.create()
|
||||
self.assertIn('not a valid SwiftSignalHandle. The tenant',
|
||||
six.text_type(st.status_reason))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_multiple_signals_same_id_complete(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
(obj_header, json.dumps({'id': 1})),
|
||||
(obj_header, json.dumps({'id': 1})),
|
||||
(obj_header, json.dumps({'id': 1})),
|
||||
|
||||
(obj_header, json.dumps({'id': 1})),
|
||||
(obj_header, json.dumps({'id': 2})),
|
||||
(obj_header, json.dumps({'id': 3})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
|
||||
@mock.patch.object(scheduler, 'wallclock')
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_multiple_signals_same_id_timeout(self, mock_name, mock_swift,
|
||||
mock_clock):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
mock_swift_object.get_object.return_value = (obj_header,
|
||||
json.dumps({'id': 1}))
|
||||
|
||||
time_now = time.time()
|
||||
time_series = [t + time_now for t in xrange(1, 100)]
|
||||
scheduler.wallclock.side_effect = time_series
|
||||
|
||||
st.create()
|
||||
self.assertIn("Resource CREATE failed: SwiftSignalTimeout",
|
||||
st.status_reason)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual("SwiftSignalTimeout: 1 of 2 received - Signal 1 "
|
||||
"recieved", wc.status_reason)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_post_complete_to_handle(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
(obj_header, json.dumps({'id': 1, 'status': "SUCCESS"})),
|
||||
(obj_header, json.dumps({'id': 1, 'status': "SUCCESS"})),
|
||||
(obj_header, json.dumps({'id': 2, 'status': "SUCCESS"})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_post_failed_to_handle(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# Create
|
||||
(obj_header, json.dumps({'id': 1, 'status': "FAILURE",
|
||||
'reason': "foo"})),
|
||||
(obj_header, json.dumps({'id': 2, 'status': "FAILURE",
|
||||
'reason': "bar"})),
|
||||
|
||||
# SwiftSignalFailure
|
||||
(obj_header, json.dumps({'id': 1, 'status': "FAILURE",
|
||||
'reason': "foo"})),
|
||||
(obj_header, json.dumps({'id': 2, 'status': "FAILURE",
|
||||
'reason': "bar"})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'FAILED'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual("SwiftSignalFailure: foo;bar", wc.status_reason)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_data(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 2)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, json.dumps({'id': 1, 'data': "foo"})),
|
||||
(obj_header, json.dumps({'id': 2, 'data': "bar"})),
|
||||
(obj_header, json.dumps({'id': 3, 'data': "baz"})),
|
||||
|
||||
# FnGetAtt call
|
||||
(obj_header, json.dumps({'id': 1, 'data': "foo"})),
|
||||
(obj_header, json.dumps({'id': 2, 'data': "bar"})),
|
||||
(obj_header, json.dumps({'id': 3, 'data': "baz"})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual(json.dumps({1: 'foo', 2: 'bar', 3: 'baz'}),
|
||||
wc.FnGetAtt('data'))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_data_noid(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, json.dumps({'data': "foo", 'reason': "bar",
|
||||
'status': "SUCCESS"})),
|
||||
(obj_header, json.dumps({'data': "dog", 'reason': "cat",
|
||||
'status': "SUCCESS"})),
|
||||
|
||||
# FnGetAtt call
|
||||
(obj_header, json.dumps({'data': "foo", 'reason': "bar",
|
||||
'status': "SUCCESS"})),
|
||||
(obj_header, json.dumps({'data': "dog", 'reason': "cat",
|
||||
'status': "SUCCESS"})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual(json.dumps({1: 'foo', 2: 'dog'}), wc.FnGetAtt('data'))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_data_nodata(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, ''),
|
||||
(obj_header, ''),
|
||||
|
||||
# FnGetAtt call
|
||||
(obj_header, ''),
|
||||
(obj_header, ''),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual(json.dumps({1: None, 2: None}), wc.FnGetAtt('data'))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_data_partial_complete(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
wc = st['test_wait_condition']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
mock_swift_object.get_object.return_value = (
|
||||
obj_header, json.dumps({'status': 'SUCCESS'}))
|
||||
|
||||
st.create()
|
||||
self.assertEqual(['SUCCESS', 'SUCCESS'], wc.get_status())
|
||||
expected = [{'status': 'SUCCESS', 'reason': 'Signal 1 recieved',
|
||||
'data': None, 'id': 1},
|
||||
{'status': 'SUCCESS', 'reason': 'Signal 2 recieved',
|
||||
'data': None, 'id': 2}]
|
||||
self.assertEqual(expected, wc.get_signals())
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_get_status_none_complete(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
wc = st['test_wait_condition']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
mock_swift_object.get_object.return_value = (obj_header, '')
|
||||
|
||||
st.create()
|
||||
self.assertEqual(['SUCCESS', 'SUCCESS'], wc.get_status())
|
||||
expected = [{'status': 'SUCCESS', 'reason': 'Signal 1 recieved',
|
||||
'data': None, 'id': 1},
|
||||
{'status': 'SUCCESS', 'reason': 'Signal 2 recieved',
|
||||
'data': None, 'id': 2}]
|
||||
self.assertEqual(expected, wc.get_signals())
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_get_status_partial_complete(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
wc = st['test_wait_condition']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
mock_swift_object.get_object.return_value = (
|
||||
obj_header, json.dumps({'id': 1, 'status': "SUCCESS"}))
|
||||
|
||||
st.create()
|
||||
self.assertEqual(['SUCCESS'], wc.get_status())
|
||||
expected = [{'status': 'SUCCESS', 'reason': 'Signal 1 recieved',
|
||||
'data': None, 'id': 1}]
|
||||
self.assertEqual(expected, wc.get_signals())
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_get_status_failure(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
wc = st['test_wait_condition']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
mock_swift_object.get_object.return_value = (
|
||||
obj_header, json.dumps({'id': 1, 'status': "FAILURE"}))
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'FAILED'), st.state)
|
||||
self.assertEqual(['FAILURE'], wc.get_status())
|
||||
expected = [{'status': 'FAILURE', 'reason': 'Signal 1 recieved',
|
||||
'data': None, 'id': 1}]
|
||||
self.assertEqual(expected, wc.get_signals())
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_getatt_token(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignalhandle_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, ''),
|
||||
(obj_header, ''),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
self.assertEqual(handle.FnGetAtt('token'), '')
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_getatt_endpoint(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignalhandle_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, ''),
|
||||
(obj_header, ''),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
expected = ('http://fake-host.com:8080/v1/AUTH_test_tenant/%s/'
|
||||
'test_st-test_wait_condition_handle-abcdefghijkl\?temp_'
|
||||
'url_sig=[0-9a-f]{40}&temp_url_expires=[0-9]{10}') % st.id
|
||||
self.assertThat(handle.FnGetAtt('endpoint'),
|
||||
MatchesRegex(expected))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_getatt_curl_cli(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignalhandle_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, ''),
|
||||
(obj_header, ''),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
expected = ('curl -i -X PUT \'http://fake-host.com:8080/v1/'
|
||||
'AUTH_test_tenant/%s/test_st-test_wait_condition_'
|
||||
'handle-abcdefghijkl\?temp_url_sig=[0-9a-f]{40}&'
|
||||
'temp_url_expires=[0-9]{10}\'') % st.id
|
||||
self.assertThat(handle.FnGetAtt('curl_cli'), MatchesRegex(expected))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_invalid_json_data(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
# st create
|
||||
(obj_header, '{"status": "SUCCESS"'),
|
||||
(obj_header, '{"status": "FAI'),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'FAILED'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual('Error: Failed to parse JSON data: {"status": '
|
||||
'"SUCCESS"', wc.status_reason)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_unknown_status(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.return_value = cont_index(obj_name, 1)
|
||||
|
||||
mock_swift_object.get_object.return_value = (
|
||||
obj_header, '{"status": "BOO"}')
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'FAILED'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual('Error: Unknown status: BOO', wc.status_reason)
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_swift_objects_deleted(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.side_effect = (
|
||||
cont_index(obj_name, 2), # Objects are there during create
|
||||
(container_header, []), # The user deleted the objects
|
||||
)
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
(obj_header, json.dumps({'id': 1})), # Objects there during create
|
||||
(obj_header, json.dumps({'id': 2})),
|
||||
(obj_header, json.dumps({'id': 3})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual("null", wc.FnGetAtt('data'))
|
||||
|
||||
@mock.patch.object(swift.SwiftClientPlugin, '_create')
|
||||
@mock.patch.object(resource.Resource, 'physical_resource_name')
|
||||
def test_swift_container_deleted(self, mock_name, mock_swift):
|
||||
st = create_stack(swiftsignal_template)
|
||||
handle = st['test_wait_condition_handle']
|
||||
|
||||
mock_swift_object = mock.Mock()
|
||||
mock_swift.return_value = mock_swift_object
|
||||
mock_swift_object.url = "http://fake-host.com:8080/v1/AUTH_1234"
|
||||
mock_swift_object.head_account.return_value = {
|
||||
'x-account-meta-temp-url-key': '123456'
|
||||
}
|
||||
obj_name = "%s-%s-abcdefghijkl" % (st.name, handle.name)
|
||||
mock_name.return_value = obj_name
|
||||
mock_swift_object.get_container.side_effect = [
|
||||
cont_index(obj_name, 2), # Objects are there during create
|
||||
swiftclient_client.ClientException("Container GET failed",
|
||||
http_status=404) # User deleted
|
||||
]
|
||||
mock_swift_object.get_object.side_effect = (
|
||||
(obj_header, json.dumps({'id': 1})), # Objects there during create
|
||||
(obj_header, json.dumps({'id': 2})),
|
||||
(obj_header, json.dumps({'id': 3})),
|
||||
)
|
||||
|
||||
st.create()
|
||||
self.assertEqual(('CREATE', 'COMPLETE'), st.state)
|
||||
wc = st['test_wait_condition']
|
||||
self.assertEqual("null", wc.FnGetAtt('data'))
|
Loading…
Reference in New Issue
Block a user