heat/heat/engine/resources/swift.py
Chmouel Boudjnah db64206035 Don't pass swift headers as None
If we set an header as None for a container swiftclient would just pass
it to httplib which convert it to string and set the None string into
it. This could not be changed in swiftclient to keep backward
compatibility lords happy so make sure that heat doesn't do that.

Closes-Bug: 1259571
Change-Id: Ida1d2cec87e44264f9a7d69a1e220b544b33b63c
2013-12-16 23:50:28 +01:00

162 lines
5.8 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.
from heat.common import exception
from heat.engine import properties
from heat.engine import resource
from heat.engine import clients
from heat.openstack.common import log as logging
from heat.openstack.common.py3kcompat import urlutils
logger = logging.getLogger(__name__)
class SwiftContainer(resource.Resource):
PROPERTIES = (
NAME, X_CONTAINER_READ, X_CONTAINER_WRITE, X_CONTAINER_META,
) = (
'name', 'X-Container-Read', 'X-Container-Write', 'X-Container-Meta',
)
properties_schema = {
NAME: properties.Schema(
properties.Schema.STRING,
_('Name for the container. If not specified, a unique name will '
'be generated.')
),
X_CONTAINER_READ: properties.Schema(
properties.Schema.STRING,
_('Specify the ACL permissions on who can read objects in the '
'container.')
),
X_CONTAINER_WRITE: properties.Schema(
properties.Schema.STRING,
_('Specify the ACL permissions on who can write objects to the '
'container.')
),
X_CONTAINER_META: properties.Schema(
properties.Schema.MAP,
_('A map of user-defined meta data to associate with the '
'container. Each key in the map will set the header '
'X-Container-Meta-{key} with the corresponding value.'),
default={}
),
}
attributes_schema = {
'DomainName': _('The host from the container URL.'),
'WebsiteURL': _('The URL of the container.'),
'RootURL': _('The parent URL of the container.'),
'ObjectCount': _('The number of objects stored in the container.'),
'BytesUsed': _('The number of bytes stored in the container.'),
'HeadContainer': _('A map containing all headers for the container.')
}
def validate(self):
'''
Validate any of the provided params
'''
#check if swiftclient is installed
if clients.swiftclient is None:
return {'Error':
'SwiftContainer unavailable due to missing swiftclient.'}
def physical_resource_name(self):
name = self.properties.get(self.NAME)
if name:
return name
return super(SwiftContainer, self).physical_resource_name()
@staticmethod
def _build_meta_headers(meta_props):
'''
Returns a new dict where each key is prepended with:
X-Container-Meta-
'''
if meta_props is None:
return {}
return dict(
('X-Container-Meta-' + k, v) for (k, v) in meta_props.items())
def handle_create(self):
"""Create a container."""
container = self.physical_resource_name()
headers = SwiftContainer._build_meta_headers(
self.properties[self.X_CONTAINER_META])
for key in (self.X_CONTAINER_READ, self.X_CONTAINER_WRITE):
if self.properties.get(key) is not None:
headers[key] = self.properties[key]
logger.debug(_('SwiftContainer create container %(container)s with '
'headers %(headers)s') % {
'container': container, 'headers': headers})
self.swift().put_container(container, headers)
self.resource_id_set(container)
def handle_delete(self):
"""Perform specified delete policy."""
logger.debug(_('SwiftContainer delete container %s') %
self.resource_id)
if self.resource_id is not None:
try:
self.swift().delete_container(self.resource_id)
except clients.swiftclient.ClientException as ex:
logger.warn(_("Delete container failed: %s") % str(ex))
def FnGetRefId(self):
return unicode(self.resource_id)
def FnGetAtt(self, key):
url, token_id = self.swift().get_auth()
parsed = list(urlutils.urlparse(url))
if key == 'DomainName':
return parsed[1].split(':')[0]
elif key == 'WebsiteURL':
return '%s://%s%s/%s' % (parsed[0], parsed[1], parsed[2],
self.resource_id)
elif key == 'RootURL':
return '%s://%s%s' % (parsed[0], parsed[1], parsed[2])
elif self.resource_id and key in (
'ObjectCount', 'BytesUsed', 'HeadContainer'):
try:
headers = self.swift().head_container(self.resource_id)
except clients.swiftclient.ClientException as ex:
logger.warn(_("Head container failed: %s") % str(ex))
return None
else:
if key == 'ObjectCount':
return headers['x-container-object-count']
elif key == 'BytesUsed':
return headers['x-container-bytes-used']
elif key == 'HeadContainer':
return headers
else:
raise exception.InvalidTemplateAttribute(resource=self.name,
key=key)
def resource_mapping():
if clients.swiftclient is None:
return {}
return {
'OS::Swift::Container': SwiftContainer,
}