heat/heat/engine/software_config_io.py

176 lines
5.3 KiB
Python

#
# 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.
"""
APIs for dealing with input and output definitions for Software Configurations.
"""
import collections
import six
from heat.common.i18n import _
from heat.common import exception
from heat.engine import constraints
from heat.engine import properties
(
IO_NAME, DESCRIPTION, TYPE,
DEFAULT, REPLACE_ON_CHANGE, VALUE,
ERROR_OUTPUT,
) = (
'name', 'description', 'type',
'default', 'replace_on_change', 'value',
'error_output',
)
TYPES = (
STRING_TYPE, NUMBER_TYPE, LIST_TYPE, JSON_TYPE, BOOLEAN_TYPE,
) = (
'String', 'Number', 'CommaDelimitedList', 'Json', 'Boolean',
)
input_config_schema = {
IO_NAME: properties.Schema(
properties.Schema.STRING,
_('Name of the input.'),
required=True
),
DESCRIPTION: properties.Schema(
properties.Schema.STRING,
_('Description of the input.')
),
TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of the value of the input.'),
default=STRING_TYPE,
constraints=[constraints.AllowedValues(TYPES)]
),
DEFAULT: properties.Schema(
properties.Schema.STRING,
_('Default value for the input if none is specified.'),
),
REPLACE_ON_CHANGE: properties.Schema(
properties.Schema.BOOLEAN,
_('Replace the deployment instead of updating it when the input '
'value changes.'),
default=False,
),
}
output_config_schema = {
IO_NAME: properties.Schema(
properties.Schema.STRING,
_('Name of the output.'),
required=True
),
DESCRIPTION: properties.Schema(
properties.Schema.STRING,
_('Description of the output.')
),
TYPE: properties.Schema(
properties.Schema.STRING,
_('Type of the value of the output.'),
default=STRING_TYPE,
constraints=[constraints.AllowedValues(TYPES)]
),
ERROR_OUTPUT: properties.Schema(
properties.Schema.BOOLEAN,
_('Denotes that the deployment is in an error state if this '
'output has a value.'),
default=False
)
}
class IOConfig(object):
"""Base class for the configuration data for a single input or output."""
def __init__(self, **config):
self._props = properties.Properties(self.schema, config)
try:
self._props.validate()
except exception.StackValidationFailed as exc:
raise ValueError(six.text_type(exc))
def name(self):
"""Return the name of the input or output."""
return self._props[IO_NAME]
def as_dict(self):
"""Return a dict representation suitable for persisting."""
return {k: v for k, v in self._props.items() if v is not None}
def __repr__(self):
return '%s(%s)' % (type(self).__name__,
', '.join('%s=%s' % (k, repr(v))
for k, v in self.as_dict().items()))
_no_value = object()
class InputConfig(IOConfig):
"""Class representing the configuration data for a single input."""
schema = input_config_schema
def __init__(self, value=_no_value, **config):
super(InputConfig, self).__init__(**config)
self._value = value
def default(self):
"""Return the default value of the input."""
return self._props[DEFAULT]
def replace_on_change(self):
return self._props[REPLACE_ON_CHANGE]
def as_dict(self):
"""Return a dict representation suitable for persisting."""
d = super(InputConfig, self).as_dict()
if not self._props[REPLACE_ON_CHANGE]:
del d[REPLACE_ON_CHANGE]
if self._value is not _no_value:
d[VALUE] = self._value
return d
def input_data(self):
"""Return a name, value pair for the input."""
value = self._value if self._value is not _no_value else None
return self.name(), value
class OutputConfig(IOConfig):
"""Class representing the configuration data for a single output."""
schema = output_config_schema
def error_output(self):
"""Return True if the presence of the output indicates an error."""
return self._props[ERROR_OUTPUT]
def check_io_schema_list(io_configs):
"""Check that an input or output schema list is of the correct type.
Raises TypeError if the list itself is not a list, or if any of the
members are not dicts.
"""
if (not isinstance(io_configs, collections.Sequence) or
isinstance(io_configs, collections.Mapping) or
isinstance(io_configs, six.string_types)):
raise TypeError('Software Config I/O Schema must be in a list')
if not all(isinstance(conf, collections.Mapping) for conf in io_configs):
raise TypeError('Software Config I/O Schema must be a dict')