Add reservation policy support

This patch adds `tosca.policies.reservation` policy_type
in TOSCA definitions and it's related unit tests.

Tacker Blueprint: https://blueprints.launchpad.net/tacker/+spec/reservation-vnfm
Tacker Spec: https://review.openstack.org/#/c/561840/
Change-Id: Ic5d790df938b40d75bc50252e1e688e9c09eb568
This commit is contained in:
nirajsingh 2018-08-23 14:56:52 +00:00 committed by niraj singh
parent f2ca5eb7aa
commit fd3c74b86b
7 changed files with 157 additions and 4 deletions

View File

@ -953,6 +953,11 @@ policy_types:
description: The TOSCA Policy Type definition that is used to declare
performance requirements for TOSCA nodes or groups of nodes.
tosca.policies.Reservation:
derived_from: tosca.policies.Root
description: The TOSCA Policy Type definition that is used to create
TOSCA nodes or group of nodes based on the reservation.
##########################################################################
# Group Type.
# Group Type represents logical grouping of TOSCA nodes that have an

View File

@ -21,9 +21,9 @@ class PolicyType(StatefulEntityType):
'''TOSCA built-in policies type.'''
SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION,
TARGETS, TRIGGERS, TYPE) = \
TARGETS, TRIGGERS, TYPE, RESERVATION) = \
('derived_from', 'metadata', 'properties', 'version',
'description', 'targets', 'triggers', 'type')
'description', 'targets', 'triggers', 'type', 'reservation')
def __init__(self, ptype, custom_def=None):
super(PolicyType, self).__init__(ptype, self.POLICY_PREFIX,
@ -55,6 +55,10 @@ class PolicyType(StatefulEntityType):
self.targets_list = self.defs[self.TARGETS]
self._validate_targets(self.targets_list, custom_def)
self.reservation = None
if self.RESERVATION in self.defs:
self.reservation = self.defs[self.RESERVATION]
def _get_parent_policies(self):
policies = {}
parent_policy = self.parent_type.type if self.parent_type else None

View File

@ -16,13 +16,15 @@ import logging
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import UnknownFieldError
from toscaparser.entity_template import EntityTemplate
from toscaparser.reservation import Reservation
from toscaparser.triggers import Triggers
from toscaparser.utils import validateutils
SECTIONS = (TYPE, METADATA, DESCRIPTION, PROPERTIES, TARGETS, TRIGGERS) = \
SECTIONS = (TYPE, METADATA, DESCRIPTION, PROPERTIES, TARGETS, TRIGGERS,
RESERVATION) = \
('type', 'metadata', 'description',
'properties', 'targets', 'triggers')
'properties', 'targets', 'triggers', 'reservation')
log = logging.getLogger('tosca')
@ -42,6 +44,7 @@ class Policy(EntityTemplate):
self.targets_list = targets
self.targets_type = targets_type
self.triggers = self._triggers(policy.get(TRIGGERS))
self.reservation = self._reservation(policy.get(RESERVATION))
self.properties = None
if 'properties' in policy:
self.properties = policy['properties']
@ -73,6 +76,13 @@ class Policy(EntityTemplate):
triggerObjs.append(triggersObj)
return triggerObjs
def _reservation(self, reservation):
reservationObjs = []
if reservation:
reservationObj = Reservation(reservation)
reservationObjs.append(reservationObj)
return reservationObjs
def _validate_keys(self):
for key in self.entity_tpl.keys():
if key not in SECTIONS:

View File

@ -0,0 +1,47 @@
# Copyright (C) 2018 NTT DATA
# All Rights Reserved.
#
# 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 logging
from toscaparser.common.exception import UnknownFieldError
from toscaparser.entity_template import EntityTemplate
from toscaparser.entity_template import MissingRequiredFieldError
SECTIONS = (START_ACTIONS, BEFORE_END_ACTIONS, END_ACTIONS, PROPERTIES) = \
('start_actions', 'before_end_actions', 'end_actions', 'properties')
log = logging.getLogger('tosca')
class Reservation(EntityTemplate):
'''Reservation defined in policies of topology template'''
def __init__(self, reservation_tpl):
self.reservation_tpl = reservation_tpl
self._validate_keys()
self._validate_missing_field()
def _validate_keys(self):
for key in self.reservation_tpl.keys():
if key not in SECTIONS:
raise UnknownFieldError(what='Reservation', field=key)
def _validate_missing_field(self):
for key in SECTIONS:
if key not in self.reservation_tpl.keys():
raise MissingRequiredFieldError(what='Reservation',
required=key)

View File

@ -181,3 +181,26 @@ policy_types:
required: false
default: 120
description: Wait time (in seconds) between consecutive scaling operations. During the cooldown period...
tosca.policies.tacker.Reservation:
derived_from: tosca.policies.Reservation
reservation:
start_actions:
type: map
entry_schema:
type: string
required: True
before_end_actions:
type: map
entry_schema:
type: string
required: True
end_actions:
type: map
entry_schema:
type: string
required: True
properties:
lease_id:
type: string
required: True

View File

@ -39,6 +39,7 @@ artif_vm_qcow2_type = ArtifactTypeDef('tosca.artifacts.'
policy_root_type = PolicyType('tosca.policies.Root')
policy_placement_type = PolicyType('tosca.policies.Placement')
policy_scaling_type = PolicyType('tosca.policies.Scaling')
policy_reservation_type = PolicyType('tosca.policies.Reservation')
policy_update_type = PolicyType('tosca.policies.Update')
policy_performance_type = PolicyType('tosca.policies.Performance')
group_type = GroupType('tosca.groups.Root')
@ -334,6 +335,18 @@ class ToscaDefTest(TestCase):
for name in policy_performance_type.defs],
key=lambda x: str(x)))
self.assertEqual('tosca.policies.Root',
policy_reservation_type.parent_type.type)
self.assertEqual({}, policy_reservation_type.parent_policies)
self.assertEqual(sorted(['tosca.policies.Root',
'The TOSCA Policy Type definition that '
'is used to create TOSCA nodes or group '
'of nodes based on the reservation.'],
key=lambda x: str(x)),
sorted([policy_reservation_type.get_policy(name)
for name in policy_reservation_type.defs],
key=lambda x: str(x)))
def test_port_spec(self):
tosca_def = EntityType.TOSCA_DEF
port_spec = tosca_def.get('tosca.datatypes.network.PortSpec')

View File

@ -21,6 +21,7 @@ from toscaparser.parameters import Output
from toscaparser.policy import Policy
from toscaparser.relationship_template import RelationshipTemplate
from toscaparser.repositories import Repository
from toscaparser.reservation import Reservation
from toscaparser.tests.base import TestCase
from toscaparser.topology_template import TopologyTemplate
from toscaparser.tosca_template import ToscaTemplate
@ -1870,3 +1871,53 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
os.path.dirname(os.path.abspath(__file__)),
"data/test_long_rel.yaml")
self.assertIsNotNone(ToscaTemplate(tpl_path))
def test_policy_reservation_valid_keyname_heat_resources(self):
tpl_snippet = '''
reservation:
start_actions: [SP_RSV]
before_end_actions: [SP_RSV]
end_actions: [noop]
properties:
lease_id: '58d2239c-f181-4915-bdcb-040f7ef911a7'
'''
reservation = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet))
name = list(reservation.keys())[0]
Reservation(reservation[name])
def test_policy_reservation_invalid_keyname_heat_resources(self):
tpl_snippet = '''
reservation:
start_actions: [SP_RSV]
before_actions: [SP_RSV]
end_actions: [noop]
properties:
lease_id: '58d2239c-f181-4915-bdcb-040f7ef911a7'
'''
reservation = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet))
name = list(reservation.keys())[0]
expectedmessage = _(
'Reservation contains unknown field '
'"before_actions". Refer to the definition '
'to verify valid values.')
err = self.assertRaises(
exception.UnknownFieldError,
lambda: Reservation(reservation[name]))
self.assertEqual(expectedmessage, err.__str__())
def test_policy_reservation_missing_key_heat_resources(self):
tpl_snippet = '''
reservation:
start_actions: [SP_RSV]
end_actions: [noop]
properties:
lease_id: '58d2239c-f181-4915-bdcb-040f7ef911a7'
'''
reservation = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet))
name = list(reservation.keys())[0]
expectedmessage = _('Reservation is missing '
'required field "before_end_actions".')
err = self.assertRaises(
exception.MissingRequiredFieldError,
lambda: Reservation(reservation[name]))
self.assertEqual(expectedmessage, err.__str__())