heat/heat/engine/identifier.py

119 lines
3.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.
import re
import urllib
import collections
class HeatIdentifier(collections.Mapping):
FIELDS = (
TENANT, STACK_NAME, STACK_ID, PATH
) = (
'tenant', 'stack_name', 'stack_id', 'path'
)
path_re = re.compile(r'stacks/([^/]+)/([^/]+)(.*)')
def __init__(self, tenant, stack_name, stack_id, path=''):
'''
Initialise a HeatIdentifier from a Tenant ID, Stack name, Stack ID
and optional path. If a path is supplied and it does not begin with
"/", a "/" will be prepended.
'''
if path and not path.startswith('/'):
path = '/' + path
self.identity = {
self.TENANT: tenant,
self.STACK_NAME: stack_name,
self.STACK_ID: str(stack_id),
self.PATH: path,
}
@classmethod
def from_arn(cls, arn):
'''
Return a new HeatIdentifier generated by parsing the supplied ARN.
'''
fields = arn.split(':')
if len(fields) < 6 or fields[0].lower() != 'arn':
raise ValueError('"%s" is not a valid ARN' % arn)
id_fragment = ':'.join(fields[5:])
path = cls.path_re.match(id_fragment)
if fields[1] != 'openstack' or fields[2] != 'heat' or not path:
raise ValueError('"%s" is not a valid Heat ARN' % arn)
return cls(urllib.unquote(fields[4]),
urllib.unquote(path.group(1)),
urllib.unquote(path.group(2)),
urllib.unquote(path.group(3)))
def arn(self):
'''
Return an ARN of the form:
arn:openstack:heat::<tenant>:stacks/<stack_name>/<stack_id><path>
'''
return 'arn:openstack:heat::%s:%s' % (urllib.quote(self.tenant, ''),
self._tenant_path())
def url_path(self):
'''
Return a URL-encoded path segment of a URL in the form:
<tenant>/stacks/<stack_name>/<stack_id><path>
'''
return '/'.join((urllib.quote(self.tenant, ''), self._tenant_path()))
def _tenant_path(self):
'''
Return a URL-encoded path segment of a URL within a particular tenant,
in the form:
stacks/<stack_name>/<stack_id><path>
'''
return 'stacks/%s/%s%s' % (urllib.quote(self.stack_name, ''),
urllib.quote(self.stack_id, ''),
urllib.quote(self.path))
def __getattr__(self, attr):
'''
Return one of the components of the identity when accessed as an
attribute.
'''
if attr not in self.FIELDS:
raise AttributeError('Unknown attribute "%s"' % attr)
return self.identity[attr]
def __getitem__(self, key):
'''Return one of the components of the identity.'''
if key not in self.FIELDS:
raise KeyError('Unknown attribute "%s"' % key)
return self.identity[key]
def __len__(self):
'''Return the number of components in an identity.'''
return len(self.FIELDS)
def __contains__(self, key):
return key in self.FIELDS
def __iter__(self):
return iter(self.FIELDS)
def __repr__(self):
return repr(dict(self))