Files
deb-heat/heat/engine/api.py
Zane Bitter bfd7fcf8f5 Eliminate DB access from the engine API
Access all data through the Stack and Resource objects.

Fixes #168

Change-Id: I0331a0ad67bcd11bb678e026ddc7b7c954517bc4
Signed-off-by: Zane Bitter <zbitter@redhat.com>
2012-07-13 16:46:20 -04:00

263 lines
7.6 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 logging
from heat.common import utils as heat_utils
from heat.engine import parser
logger = logging.getLogger('heat.engine.manager')
PARAM_KEYS = (
PARAM_TIMEOUT,
PARAM_USER_KEY_re,
PARAM_USER_VALUE_fmt,
) = (
'TimeoutInMinutes',
re.compile(r'Parameters\.member\.(.*?)\.ParameterKey$'),
'Parameters.member.%s.ParameterValue',
)
def extract_user_params(params):
'''
Extract a dictionary of user parameters (to e.g. a stack create command)
from the parameter dictionary passed through the API.
In the API parameters, each user parameter appears as two key-value pairs
with keys of the form:
Parameters.member.1.ParameterKey
Parameters.member.1.ParameterValue
'''
def get_param_pairs():
for k in params:
keymatch = PARAM_USER_KEY_re.match(k)
if keymatch:
key = params[k]
v = PARAM_USER_VALUE_fmt % keymatch.group(1)
try:
value = params[v]
except KeyError:
logger.error('Could not apply parameter %s' % key)
yield (key, value)
return dict(get_param_pairs())
def extract_args(params):
'''
Extract any arguments passed as parameters through the API and return them
as a dictionary.
'''
kwargs = {}
try:
timeout_mins = int(params.get(PARAM_TIMEOUT, 0))
except (ValueError, TypeError):
logger.exception('create timeout conversion')
else:
if timeout_mins > 0:
kwargs['timeout_mins'] = timeout_mins
return kwargs
def _filter_keys(data, keys):
'''
Filter the provided data so that only the dictionary keys specified are
present. If keys is None, return all of the data.
'''
if keys is not None:
data = dict((k, v) for (k, v) in data.iteritems() if k in keys)
return data
STACK_KEYS = (
STACK_NAME, STACK_ID,
STACK_CREATION_TIME, STACK_UPDATED_TIME, STACK_DELETION_TIME,
STACK_NOTIFICATION_TOPICS,
STACK_DESCRIPTION, STACK_TMPL_DESCRIPTION,
STACK_PARAMETERS, STACK_OUTPUTS,
STACK_STATUS, STACK_STATUS_DATA,
STACK_TIMEOUT,
) = (
'StackName', 'StackId',
'CreationTime', 'LastUpdatedTime', 'DeletionTime',
'NotificationARNs',
'Description', 'TemplateDescription',
'Parameters', 'Outputs',
'StackStatus', 'StackStatusReason',
PARAM_TIMEOUT,
)
KEYS_STACK = (
STACK_NAME, STACK_ID,
STACK_CREATION_TIME, STACK_UPDATED_TIME,
STACK_NOTIFICATION_TOPICS,
STACK_DESCRIPTION,
STACK_PARAMETERS, STACK_DESCRIPTION, STACK_OUTPUTS,
STACK_STATUS, STACK_STATUS_DATA,
STACK_TIMEOUT,
)
KEYS_STACK_SUMMARY = (
STACK_CREATION_TIME, STACK_DELETION_TIME,
STACK_UPDATED_TIME,
STACK_ID, STACK_NAME,
STACK_TMPL_DESCRIPTION,
STACK_STATUS, STACK_STATUS_DATA,
)
STACK_OUTPUT_KEYS = (
OUTPUT_DESCRIPTION,
OUTPUT_KEY, OUTPUT_VALUE,
) = (
'Description',
'OutputKey', 'OutputValue',
)
def format_stack_outputs(stack, outputs):
'''
Return a representation of the given output template for the given stack
that matches the API output expectations.
'''
def format_stack_output(k):
return {OUTPUT_DESCRIPTION: outputs[k].get('Description',
'No description given'),
OUTPUT_KEY: k,
OUTPUT_VALUE: stack.output(k)}
return [format_stack_output(key) for key in outputs]
def format_stack(stack, keys=None):
'''
Return a representation of the given stack that matches the API output
expectations.
'''
info = {
STACK_NAME: stack.name,
STACK_ID: stack.id,
STACK_CREATION_TIME: heat_utils.strtime(stack.created_time),
STACK_UPDATED_TIME: heat_utils.strtime(stack.updated_time),
STACK_NOTIFICATION_TOPICS: [], # TODO Not implemented yet
STACK_PARAMETERS: stack.t[parser.PARAMETERS],
STACK_DESCRIPTION: stack.t[parser.DESCRIPTION],
STACK_TMPL_DESCRIPTION: stack.t[parser.DESCRIPTION],
STACK_STATUS: stack.state,
STACK_STATUS_DATA: stack.state_description,
STACK_TIMEOUT: stack.timeout_mins,
}
# only show the outputs on a completely created stack
if stack.state == stack.CREATE_COMPLETE:
info[STACK_OUTPUTS] = format_stack_outputs(stack, stack.outputs)
return _filter_keys(info, keys)
RES_KEYS = (
RES_DESCRIPTION, RES_UPDATED_TIME,
RES_NAME, RES_PHYSICAL_ID, RES_METADATA,
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
RES_STACK_ID, RES_STACK_NAME,
RES_TIMESTAMP,
) = (
'Description', 'LastUpdatedTimestamp',
'LogicalResourceId', 'PhysicalResourceId', 'Metadata',
'ResourceStatus', 'ResourceStatusReason', 'ResourceType',
STACK_ID, STACK_NAME,
'Timestamp',
)
KEYS_RESOURCE_DETAIL = (
RES_DESCRIPTION, RES_UPDATED_TIME,
RES_NAME, RES_PHYSICAL_ID, RES_METADATA,
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
RES_STACK_ID, RES_STACK_NAME,
)
KEYS_RESOURCE = (
RES_DESCRIPTION,
RES_NAME, RES_PHYSICAL_ID,
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
RES_STACK_ID, RES_STACK_NAME,
RES_TIMESTAMP,
)
KEYS_RESOURCE_SUMMARY = (
RES_UPDATED_TIME,
RES_NAME, RES_PHYSICAL_ID,
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
)
def format_stack_resource(resource, keys=None):
'''
Return a representation of the given resource that matches the API output
expectations.
'''
last_updated_time = resource.updated_time or resource.created_time
attrs = {
RES_DESCRIPTION: resource.parsed_template().get('Description', ''),
RES_UPDATED_TIME: heat_utils.strtime(last_updated_time),
RES_NAME: resource.name,
RES_PHYSICAL_ID: resource.instance_id or '',
RES_METADATA: resource.metadata,
RES_STATUS: resource.state,
RES_STATUS_DATA: resource.state_description,
RES_TYPE: resource.t['Type'],
RES_STACK_ID: resource.stack.id,
RES_STACK_NAME: resource.stack.name,
RES_TIMESTAMP: heat_utils.strtime(last_updated_time),
}
return _filter_keys(attrs, keys)
EVENT_KEYS = (
EVENT_ID,
EVENT_STACK_ID, EVENT_STACK_NAME,
EVENT_TIMESTAMP,
EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID,
EVENT_RES_STATUS, EVENT_RES_STATUS_DATA, EVENT_RES_TYPE,
EVENT_RES_PROPERTIES,
) = (
'EventId',
STACK_ID, STACK_NAME,
RES_TIMESTAMP,
RES_NAME, RES_PHYSICAL_ID,
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
'ResourceProperties',
)
def format_event(event, keys=None):
s = event.stack
attrs = {
EVENT_ID: event.id,
EVENT_STACK_ID: s.id,
EVENT_STACK_NAME: s.name,
EVENT_TIMESTAMP: heat_utils.strtime(event.created_at),
EVENT_RES_NAME: event.logical_resource_id,
EVENT_RES_PHYSICAL_ID: event.physical_resource_id,
EVENT_RES_STATUS: event.name,
EVENT_RES_STATUS_DATA: event.resource_status_reason,
EVENT_RES_TYPE: event.resource_type,
EVENT_RES_PROPERTIES: event.resource_properties,
}
return _filter_keys(attrs, keys)