RFE alarm monitor: Fix hardcoded metadata,add func. test

This patch will focus on:
1. Fixing hardcoded metadata
2. Adding functional test for alarm monitor
3. Refactoring tosca template for alarm monitor
4. Refactoring scaling in/out support in alarm monitor
5. Supporting multi-trigger

Partial-bug: #1630614
Change-Id: Ic5d0046d0dc0b4381713bda01c485cecae17abea
changes/79/382479/28
doantungbk 6 years ago
parent a1dd7fd73d
commit 0eafa5b1bf

@ -44,49 +44,129 @@ described firstly like other TOSCA templates in Tacker.
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: respawn
actions: [respawn]
Alarm framework already supported the some default backend actions like
**respawn, log, and log_and_kill**.
**scaling, respawn, log, and log_and_kill**.
Tacker users could change the desired action as described in the above example.
Until now, the backend actions could be pointed to the specific policy which
is also described in TOSCA template like scaling policy. The integration between
alarming monitoring and auto-scaling was also supported by Alarm monitor in Tacker:
alarming monitoring and scaling was also supported by Alarm monitor in Tacker:
.. code-block:: yaml
policies:
- SP1:
type: tosca.policies.tacker.Scaling
properties:
increment: 1
cooldown: 120
min_instances: 1
max_instances: 3
default_instances: 2
targets: [VDU1]
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 600
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: SP1
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: Demo example
metadata:
template_name: sample-tosca-vnfd
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
VDU2:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP2:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU2
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
policies:
- SP1:
type: tosca.policies.tacker.Scaling
properties:
increment: 1
cooldown: 120
min_instances: 1
max_instances: 3
default_instances: 2
targets: [VDU1,VDU2]
- vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
vdu_hcpu_usage_scaling_out:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 600
evaluations: 1
method: avg
comparison_operator: gt
metadata: SG1
actions: [SP1]
vdu_lcpu_usage_scaling_in:
targets: [VDU1, VDU2]
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 10
constraint: utilization less_than 10%
period: 600
evaluations: 1
method: avg
comparison_operator: lt
metadata: SG1
actions: [SP1]
**NOTE:**
metadata defined in VDU properties must be matched with metadata in monitoring policy
How to setup environment
~~~~~~~~~~~~~~~~~~~~~~~~
@ -112,45 +192,47 @@ is successfully passed to Ceilometer, Tacker users could use CLI:
.. code-block:: console
$ceilometer alarm-list
$aodh alarm list
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+------------+-------------------------------------+------------------+
| Alarm ID | Name | State | Severity | Enabled | Continuous | Alarm condition | Time constraints |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+------------+-------------------------------------+------------------+
| f6a89242-d849-4a1a-9eb5-de4c0730252f | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-d4900104-6257-4084-8506-9fa6895d1294-vdu1_cpu_usage_monitoring_policy-7rt36gqbmuqo | insufficient data | low | True | True | avg(cpu_util) > 15.0 during 1 x 65s | None |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+------------+-------------------------------------+------------------
+--------------------------------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+
| alarm_id | type | name | state | severity | enabled |
+--------------------------------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+
| 6f2336b9-e0a2-4e33-88be-bc036192b42b | threshold | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-a0f60b00-ad3d-4769-92ef-e8d9518da2c8-vdu_lcpu_scaling_in-smgctfnc3ql5 | insufficient data | low | True |
| e049f0d3-09a8-46c0-9b88-e61f1f524aab | threshold | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-a0f60b00-ad3d-4769-92ef-e8d9518da2c8-vdu_hcpu_usage_scaling_out-lubylov5g6xb | insufficient data | low | True |
+--------------------------------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+
.. code-block:: console
$ ceilometer alarm-show 35a80852-e24f-46ed-bd34-e2f831d00172
+---------------------------+--------------------------------------------------------------------------+
| Property | Value |
+---------------------------+--------------------------------------------------------------------------+
| alarm_actions | ["http://pinedcn:9890/v1.0/vnfs/d4900104-6257-4084-8506-9fa6895d1294/vdu |
| | 1_cpu_usage_monitoring_policy/SP1/i42kd018"] |
| alarm_id | f6a89242-d849-4a1a-9eb5-de4c0730252f |
| comparison_operator | gt |
| description | utilization greater_than 50% |
| enabled | True |
| evaluation_periods | 1 |
| exclude_outliers | False |
| insufficient_data_actions | None |
| meter_name | cpu_util |
| name | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-d4900104-6257-40 |
| | 84-8506-9fa6895d1294-vdu1_cpu_usage_monitoring_policy-7rt36gqbmuqo |
| ok_actions | None |
| period | 65 |
| project_id | abdc74442be44b9486ca5e32a980bca1 |
| query | metadata.user_metadata.vnf_id == d4900104-6257-4084-8506-9fa6895d1294 |
| repeat_actions | True |
| severity | low |
| state | insufficient data |
| statistic | avg |
| threshold | 15.0 |
| type | threshold |
| user_id | 25a691398e534893b8627f3762712515 |
+---------------------------+--------------------------------------------------------------------------+
$aodh alarm show 6f2336b9-e0a2-4e33-88be-bc036192b42b
+---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
| alarm_actions | [u'http://pinedcn:9890/v1.0/vnfs/a0f60b00-ad3d-4769-92ef-e8d9518da2c8/vdu_lcpu_scaling_in/SP1-in/yl7kh5qd'] |
| alarm_id | 6f2336b9-e0a2-4e33-88be-bc036192b42b |
| comparison_operator | lt |
| description | utilization less_than 10% |
| enabled | True |
| evaluation_periods | 1 |
| exclude_outliers | False |
| insufficient_data_actions | None |
| meter_name | cpu_util |
| name | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-a0f60b00-ad3d-4769-92ef-e8d9518da2c8-vdu_lcpu_scaling_in-smgctfnc3ql5 |
| ok_actions | None |
| period | 600 |
| project_id | 3db801789c9e4b61b14ce448c9e7fb6d |
| query | metadata.user_metadata.vnf_id = a0f60b00-ad3d-4769-92ef-e8d9518da2c8 |
| repeat_actions | True |
| severity | low |
| state | insufficient data |
| state_timestamp | 2016-11-16T18:39:30.134954 |
| statistic | avg |
| threshold | 10.0 |
| time_constraints | [] |
| timestamp | 2016-11-16T18:39:30.134954 |
| type | threshold |
| user_id | a783e8a94768484fb9a43af03c6426cb |
+---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
How to trigger alarms:
@ -167,7 +249,7 @@ Another way could be used to check if backend action is handled well in Tacker:
.. code-block::ini
curl -H "Content-Type: application/json" -X POST -d '{"alarm_id": "35a80852-e24f-46ed-bd34-e2f831d00172", "current": "alarm"}' http://ubuntu:9890/v1.0/vnfs/6f3e523d-9e12-4973-a2e8-ea04b9601253/vdu1_cpu_usage_monitoring_policy/respawn/g0jtsxu9
curl -H "Content-Type: application/json" -X POST -d '{"alarm_id": "35a80852-e24f-46ed-bd34-e2f831d00172", "current": "alarm"}' http://pinedcn:9890/v1.0/vnfs/a0f60b00-ad3d-4769-92ef-e8d9518da2c8/vdu_lcpu_scaling_in/SP1-in/yl7kh5qd
Then, users can check Horizon to know if vnf is respawned. Please note that the url used
in the above command could be captured from "**ceilometer alarm-show** command as shown before.

@ -18,6 +18,7 @@ topology_template:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: VDU1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
@ -40,7 +41,7 @@ topology_template:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
vdu_hcpu_usage_respawning:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
@ -52,6 +53,5 @@ topology_template:
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: respawn
metadata: VDU1
actions: [respawn]

@ -18,6 +18,7 @@ topology_template:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
@ -29,6 +30,30 @@ topology_template:
node: VL1
- virtualBinding:
node: VDU1
VDU2:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP2:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU2
VL1:
type: tosca.nodes.nfv.VL
@ -45,12 +70,12 @@ topology_template:
min_instances: 1
max_instances: 3
default_instances: 2
targets: [VDU1]
targets: [VDU1,VDU2]
- vdu1_cpu_usage_monitoring_policy:
- vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
vdu_hcpu_usage_scaling_out:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
@ -62,6 +87,21 @@ topology_template:
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: SP1
metadata: SG1
actions: [SP1]
vdu_lcpu_usage_scaling_in:
targets: [VDU1, VDU2]
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 10
constraint: utilization less_than 10%
period: 600
evaluations: 1
method: avg
comparison_operator: lt
metadata: SG1
actions: [SP1]

@ -249,6 +249,10 @@ class AlarmUrlInvalid(BadRequest):
message = _("Invalid alarm url for VNF %(vnf_id)s")
class TriggerNotFound(NotFound):
message = _("Trigger %(trigger_name)s does not exist for VNF %(vnf_id)s")
class VnfPolicyNotFound(NotFound):
message = _("Policy %(policy)s does not exist for VNF %(vnf_id)s")

@ -153,6 +153,10 @@ class VNFInactive(exceptions.InvalidInput):
message = _("VNF %(vnf_id)s is not in Active state %(message)s")
class MetadataNotMatched(exceptions.InvalidInput):
message = _("Metadata for alarm policy is not matched")
def _validate_service_type_list(data, valid_values=None):
if not isinstance(data, list):
msg = _("invalid data format for service list: '%s'") % data

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
POLICY_ALARMING = 'tosca.policies.tacker.Alarming'
DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify']
VNF_CIRROS_CREATE_TIMEOUT = 300
VNF_CIRROS_DELETE_TIMEOUT = 300
VNF_CIRROS_DEAD_TIMEOUT = 250

@ -0,0 +1,57 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: Demo example
metadata:
template_name: sample-tosca-vnfd
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: VDU1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
policies:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
vdu_hcpu_usage_respawning:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 600
evaluations: 1
method: avg
comparison_operator: gt
metadata: VDU1
actions: [respawn]

@ -0,0 +1,82 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: Demo example
metadata:
template_name: sample-tosca-vnfd
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
policies:
- SP1:
type: tosca.policies.tacker.Scaling
properties:
increment: 1
cooldown: 60
min_instances: 1
max_instances: 3
default_instances: 2
targets: [VDU1]
- vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
vdu_hcpu_usage_scaling_out:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 600
evaluations: 1
method: avg
comparison_operator: gt
metadata: SG1
actions: [SP1]
vdu_hcpu_usage_scaling_in:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 10
constraint: utilization less_than 10%
period: 600
evaluations: 1
method: avg
comparison_operator: lt
metadata: SG1
actions: [SP1]

@ -0,0 +1,150 @@
#
#
# 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 json
import time
from tacker.plugins.common import constants as evt_constants
from tacker.tests import constants
from tacker.tests.functional import base
from tacker.tests.utils import read_file
import yaml
class VnfTestAlarmMonitor(base.BaseTackerTest):
def _test_vnf_tosca_alarm(self, vnfd_file, vnf_name):
vnf_trigger_path = '/vnfs/%s/triggers'
data = dict()
data['tosca'] = read_file(vnfd_file)
tosca_dict = yaml.safe_load(data['tosca'])
toscal = data['tosca']
tosca_arg = {'vnfd': {'name': vnf_name,
'attributes': {'vnfd': toscal}}}
# Create vnfd with tosca template
vnfd_instance = self.client.create_vnfd(body=tosca_arg)
self.assertIsNotNone(vnfd_instance)
# Create vnf with vnfd_id
vnfd_id = vnfd_instance['vnfd']['id']
vnf_arg = {'vnf': {'vnfd_id': vnfd_id, 'name': vnf_name}}
vnf_instance = self.client.create_vnf(body=vnf_arg)
self.validate_vnf_instance(vnfd_instance, vnf_instance)
vnf_id = vnf_instance['vnf']['id']
def _waiting_time(count):
self.wait_until_vnf_active(
vnf_id,
constants.VNF_CIRROS_CREATE_TIMEOUT,
constants.ACTIVE_SLEEP_TIME)
vnf = self.client.show_vnf(vnf_id)['vnf']
# {"VDU1": ["10.0.0.14", "10.0.0.5"]}
self.assertEqual(count, len(json.loads(vnf['mgmt_url'])['VDU1']))
def trigger_vnf(vnf, policy_name, policy_action):
credential = 'g0jtsxu9'
body = {"trigger": {'policy_name': policy_name,
'action_name': policy_action,
'params': {
'data': {'alarm_id': '35a80852-e24f-46ed-bd34-e2f831d00172', 'current': 'alarm'}, # noqa
'credential': credential}
}
}
self.client.post(vnf_trigger_path % vnf, body)
def _inject_monitoring_policy(vnfd_dict):
if vnfd_dict.get('tosca_definitions_version'):
polices = vnfd_dict['topology_template'].get('policies', [])
mon_policy = dict()
for policy_dict in polices:
for name, policy in policy_dict.items():
if policy['type'] == constants.POLICY_ALARMING:
triggers = policy['triggers']
for trigger_name, trigger_dict in triggers.items():
policy_action_list = trigger_dict['actions']
for policy_action in policy_action_list:
mon_policy[trigger_name] = policy_action
return mon_policy
def verify_policy(policy_dict, kw_policy):
for name, action in policy_dict.items():
if kw_policy in name:
return name
# trigger alarm
monitoring_policy = _inject_monitoring_policy(tosca_dict)
for mon_policy_name, mon_policy_action in monitoring_policy.items():
if mon_policy_action in constants.DEFAULT_ALARM_ACTIONS:
self.wait_until_vnf_active(
vnf_id,
constants.VNF_CIRROS_CREATE_TIMEOUT,
constants.ACTIVE_SLEEP_TIME)
trigger_vnf(vnf_id, mon_policy_name, mon_policy_action)
else:
if 'scaling_out' in mon_policy_name:
_waiting_time(2)
time.sleep(constants.SCALE_WINDOW_SLEEP_TIME)
# scaling-out backend action
scaling_out_action = mon_policy_action + '-out'
trigger_vnf(vnf_id, mon_policy_name, scaling_out_action)
_waiting_time(3)
scaling_in_name = verify_policy(monitoring_policy,
kw_policy='scaling_in')
if scaling_in_name:
time.sleep(constants.SCALE_WINDOW_SLEEP_TIME)
# scaling-in backend action
scaling_in_action = mon_policy_action + '-in'
trigger_vnf(vnf_id, scaling_in_name, scaling_in_action)
_waiting_time(2)
self.verify_vnf_crud_events(
vnf_id, evt_constants.RES_EVT_SCALE,
evt_constants.ACTIVE, cnt=2)
self.verify_vnf_crud_events(
vnf_id, evt_constants.RES_EVT_SCALE,
evt_constants.PENDING_SCALE_OUT, cnt=1)
self.verify_vnf_crud_events(
vnf_id, evt_constants.RES_EVT_SCALE,
evt_constants.PENDING_SCALE_IN, cnt=1)
# Delete vnf_instance with vnf_id
try:
self.client.delete_vnf(vnf_id)
except Exception:
assert False, ("Failed to delete vnf %s after the monitor test" %
vnf_id)
# Verify VNF monitor events captured for states, ACTIVE and DEAD
vnf_state_list = [evt_constants.ACTIVE, evt_constants.DEAD]
self.verify_vnf_monitor_events(vnf_id, vnf_state_list)
# Delete vnfd_instance
self.addCleanup(self.client.delete_vnfd, vnfd_id)
self.addCleanup(self.wait_until_vnf_delete, vnf_id,
constants.VNF_CIRROS_DELETE_TIMEOUT)
def test_vnf_alarm_respawn(self):
self._test_vnf_tosca_alarm(
'sample-tosca-alarm-respawn.yaml',
'alarm and respawn vnf')
def test_vnf_alarm_scale(self):
self._test_vnf_tosca_alarm(
'sample-tosca-alarm-scale.yaml',
'alarm and scale vnf')

@ -250,8 +250,7 @@ class TestDeviceHeat(base.TestCase):
tosca_tpl_name,
hot_tpl_name,
param_values='',
is_monitor=True,
is_alarm=False):
is_monitor=True):
tosca_tpl = _get_template(tosca_tpl_name)
exp_tmpl = self._get_expected_vnfd(tosca_tpl)
tosca_hw_dict = yaml.safe_load(_get_template(hot_tpl_name))
@ -279,11 +278,9 @@ class TestDeviceHeat(base.TestCase):
'"respawn"}, "parameters": {"count": 3, '
'"interval": 10}, "monitoring_params": '
'{"count": 3, "interval": 10}}}}}'})
if is_alarm:
dvc['attributes'].update({'alarm_url': ''})
return dvc
def _get_dummy_tosca_vnf(self, template, input_params='', is_alarm=False):
def _get_dummy_tosca_vnf(self, template, input_params=''):
tosca_template = _get_template(template)
vnf = utils.get_dummy_device_obj()
@ -292,24 +289,20 @@ class TestDeviceHeat(base.TestCase):
vnf['vnfd'] = dtemplate
vnf['attributes'] = {}
vnf['attributes']['param_values'] = input_params
if is_alarm:
vnf['attributes']['alarm_url'] = ''
return vnf
def _test_assert_equal_for_tosca_templates(self, tosca_tpl_name,
hot_tpl_name,
input_params='',
files=None,
is_monitor=True,
is_alarm=False):
vnf = self._get_dummy_tosca_vnf(tosca_tpl_name, input_params, is_alarm)
is_monitor=True):
vnf = self._get_dummy_tosca_vnf(tosca_tpl_name, input_params)
expected_result = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738'
expected_fields = self._get_expected_fields_tosca(hot_tpl_name)
expected_vnf = self._get_expected_tosca_vnf(tosca_tpl_name,
hot_tpl_name,
input_params,
is_monitor,
is_alarm)
is_monitor)
result = self.heat_driver.create(plugin=None, context=self.context,
vnf=vnf,
auth_attr=utils.get_vim_auth_obj())
@ -459,8 +452,7 @@ class TestDeviceHeat(base.TestCase):
def test_create_tosca_with_alarm_monitoring(self):
self._test_assert_equal_for_tosca_templates(
'tosca_alarm.yaml',
'hot_tosca_alarm.yaml',
is_monitor=False,
is_alarm=True
'tosca_alarm_respawn.yaml',
'hot_tosca_alarm_respawn.yaml',
is_monitor=False
)

@ -0,0 +1,24 @@
heat_template_version: 2013-05-23
description: 'sample-tosca-vnfd-scaling
'
outputs:
mgmt_ip-VDU1:
value:
get_attr: [CP1, fixed_ips, 0, ip_address]
parameters: {}
resources:
CP1:
properties: {network: net_mgmt, port_security_enabled: false}
type: OS::Neutron::Port
VDU1:
properties:
availability_zone: nova
config_drive: false
flavor: m1.tiny
image: cirros-0.3.4-x86_64-uec
metadata: {metering.vnf: SG1}
networks:
- port: {get_resource: CP1}
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server

@ -0,0 +1,41 @@
heat_template_version: 2013-05-23
description: 'An exception will be raised when having the mismatched metadata
(metadata is described in monitoring policy but unavailable in VDU properties).
'
outputs:
mgmt_ip-VDU1:
value:
get_attr: [CP1, fixed_ips, 0, ip_address]
parameters: {}
resources:
VDU1:
properties:
availability_zone: nova
config_drive: false
flavor: {get_resource: VDU1_flavor}
image: cirros-0.3.4-x86_64-uec
networks:
- port: {get_resource: CP1}
user_data_format: SOFTWARE_CONFIG
type: OS::Nova::Server
CP1:
properties: {network: net_mgmt, port_security_enabled: false}
type: OS::Neutron::Port
VDU1_flavor:
type: OS::Nova::Flavor
properties:
disk: 1
ram: 512
vcpus: 2
vdu_hcpu_usage_respawning:
type: OS::Aodh::Alarm
properties:
description: utilization greater_than 50%
meter_name: cpu_util
threshold: 50
period: 60
statistic: average
evaluation_periods: 1
comparison_operator: gt
'matching_metadata': {'metadata.user_metadata.vnf': 'VDU1'}

@ -18,6 +18,7 @@ resources:
networks:
- port: {get_resource: CP1}
user_data_format: SOFTWARE_CONFIG
metadata: {'metering.vnf': 'VDU1'}
type: OS::Nova::Server
CP1:
properties: {network: net_mgmt, port_security_enabled: false}
@ -28,7 +29,7 @@ resources:
disk: 1
ram: 512
vcpus: 2
vdu1_cpu_usage_monitoring_policy:
vdu_hcpu_usage_respawning:
type: OS::Aodh::Alarm
properties:
description: utilization greater_than 50%
@ -38,4 +39,4 @@ resources:
statistic: average
evaluation_periods: 1
comparison_operator: gt
'matching_metadata': {'metadata.user_metadata.vnf': 'VDU1'}

@ -0,0 +1,49 @@
heat_template_version: 2013-05-23
description: Tacker scaling template
parameters: {}
resources:
G1:
properties:
cooldown: 60
desired_capacity: 2
max_size: 3
min_size: 1
resource: {type: scaling.yaml}
type: OS::Heat::AutoScalingGroup
SP1_scale_in:
properties:
adjustment_type: change_in_capacity
auto_scaling_group_id: {get_resource: G1}
cooldown: 60
scaling_adjustment: '-1'
type: OS::Heat::ScalingPolicy
SP1_scale_out:
properties:
adjustment_type: change_in_capacity
auto_scaling_group_id: {get_resource: G1}
cooldown: 60
scaling_adjustment: 1
type: OS::Heat::ScalingPolicy
vdu_hcpu_usage_scaling_out:
type: OS::Aodh::Alarm
properties:
description: utilization greater_than 50%
meter_name: cpu_util
statistic: avg
period: 600
evaluation_periods: 1
threshold: 50
matching_metadata: {'metadata.user_metadata.vnf': SG1}
comparison_operator: gt
vdu_lcpu_usage_scaling_in:
type: OS::Aodh::Alarm
properties:
description: utilization less_than 10%
meter_name: cpu_util
statistic: avg
period: 600
evaluation_periods: 1
threshold: 10
matching_metadata: {'metadata.user_metadata.vnf': SG1}
comparison_operator: lt

@ -18,6 +18,7 @@ topology_template:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: VDU1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
@ -40,7 +41,7 @@ topology_template:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
vdu_hcpu_usage_respawning:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
@ -52,6 +53,5 @@ topology_template:
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: respawn
metadata: VDU1
actions: [respawn]

@ -18,6 +18,7 @@ topology_template:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: SG1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
@ -50,7 +51,7 @@ topology_template:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
vdu_hcpu_usage_scaling_out:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
@ -62,6 +63,5 @@ topology_template:
evaluations: 1
method: avg
comparison_operator: gt
action:
resize_compute:
action_name: SP1
metadata: SG1
actions: [SP1]

@ -0,0 +1,60 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: >
An exception will be raised when having the mismatched metadata
(metadata is described in monitoring policy but unavailable in
VDU properties).
metadata:
template_name: sample-tosca-vnfd
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
disk_size: 1 GB
mem_size: 512 MB
num_cpus: 2
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
CP1:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
policies:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
vdu_hcpu_usage_respawning:
event_type:
type: tosca.events.resource.utilization
implementation: Ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 60
evaluations: 1
method: average
comparison_operator: gt
metadata: VDU1
actions: ''

@ -18,6 +18,8 @@ topology_template:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
metadata: {metering.vnf: VDU1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
@ -40,7 +42,7 @@ topology_template:
- vdu1_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
resize_compute:
vdu_hcpu_usage_respawning:
event_type:
type: tosca.events.resource.utilization
implementation: Ceilometer
@ -52,5 +54,5 @@ topology_template:
evaluations: 1
method: average
comparison_operator: gt
action:
resize_compute: ''
metadata: VDU1
actions: ''

@ -0,0 +1,78 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: sample-tosca-vnfd-scaling
metadata:
template_name: sample-tosca-vnfd-scaling
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
properties:
image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop
availability_zone: nova
flavor: m1.tiny
metadata: {metering.vnf: SG1}
CP1:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
policies:
- SP1:
type: tosca.policies.tacker.Scaling
properties:
increment: 1
cooldown: 60
min_instances: 1
max_instances: 3
default_instances: 2
targets: [VDU1]
- vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming
triggers:
vdu_hcpu_usage_scaling_out:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 50
constraint: utilization greater_than 50%
period: 600
evaluations: 1
method: avg
comparison_operator: gt
metadata: SG1
actions: [SP1]
vdu_lcpu_usage_scaling_in:
event_type:
type: tosca.events.resource.utilization
implementation: ceilometer
metrics: cpu_util
condition:
threshold: 10
constraint: utilization less_than 10%
period: 600
evaluations: 1
method: avg
comparison_operator: lt
metadata: SG1
actions: [SP1]

@ -457,3 +457,26 @@ class TestOpenStack(base.TestCase):
'test_tosca_mac_ip.yaml',
'hot_tosca_mac_ip.yaml'
)
def test_create_tosca_alarm_respawn(self):
self._test_assert_equal_for_tosca_templates(
'tosca_alarm_respawn.yaml',
'hot_tosca_alarm_respawn.yaml',
is_monitor=False
)
def test_create_tosca_alarm_scale(self):
self._test_assert_equal_for_tosca_templates(
'tosca_alarm_scale.yaml',
'hot_tosca_alarm_scale.yaml',
files={'scaling.yaml': 'hot_alarm_scale_custom.yaml'},
is_monitor=False
)
def test_create_tosca_with_alarm_monitoring_not_matched(self):
self.assertRaises(vnfm.MetadataNotMatched,
self._test_assert_equal_for_tosca_templates,
'tosca_alarm_metadata.yaml',
'hot_tosca_alarm_metadata.yaml',
is_monitor=False
)

@ -394,17 +394,17 @@ class TestVNFMPlugin(db_base.SqlTestCase):
dummy_vnf['vim_id'] = '437ac8ef-a8fb-4b6e-8d8a-a5e86a376e8b'
return dummy_vnf
def _test_create_vnf_trigger(self, action_value):
def _test_create_vnf_trigger(self, policy_name, action_value):
vnf_id = "6261579e-d6f3-49ad-8bc3-a9cb974778fe"
trigger_request = {"trigger": {"action_name": action_value, "params": {
"credential": "026kll6n", "data": {"current": "alarm",
'alarm_id':
"b7fa9ffd-0a4f-4165-954b-5a8d0672a35f"}},
"policy_name": "vdu1_cpu_usage_monitoring_policy"}}
"policy_name": policy_name}}
expected_result = {"action_name": action_value, "params": {
"credential": "026kll6n", "data": {"current": "alarm",
"alarm_id": "b7fa9ffd-0a4f-4165-954b-5a8d0672a35f"}},
"policy_name": "vdu1_cpu_usage_monitoring_policy"}
"policy_name": policy_name}
self._vnf_alarm_monitor.process_alarm_for_vnf.return_value = True
trigger_result = self.vnfm_plugin.create_vnf_trigger(
self.context, vnf_id, trigger_request)
@ -418,7 +418,8 @@ class TestVNFMPlugin(db_base.SqlTestCase):
mock_get_vnf.return_value = dummy_vnf
mock_action_class = mock.Mock()
mock_get_policy.return_value = mock_action_class
self._test_create_vnf_trigger(action_value="respawn")
self._test_create_vnf_trigger(policy_name="vdu_hcpu_usage_respawning",
action_value="respawn")
mock_get_policy.assert_called_once_with('respawn', 'test_vim')
mock_action_class.execute_action.assert_called_once_with(
self.vnfm_plugin, dummy_vnf)
@ -432,7 +433,8 @@ class TestVNFMPlugin(db_base.SqlTestCase):
mock_action_class = mock.Mock()
mock_get_policy.return_value = mock_action_class
scale_body = {'scale': {'policy': 'SP1', 'type': 'out'}}
self._test_create_vnf_trigger(action_value="SP1")
self._test_create_vnf_trigger(policy_name="vdu_hcpu_usage_scaling_out",
action_value="SP1-out")
mock_get_policy.assert_called_once_with('scaling', 'test_vim')
mock_action_class.execute_action.assert_called_once_with(
self.vnfm_plugin, dummy_vnf, scale_body)

@ -67,7 +67,7 @@ class TestSamples(testtools.TestCase):
self.assertIsNotNone(
tosca,
"Tosca parser failed to parse %s" % f)
utils.post_process_template(tosca)
hot = None
try:
hot = tosca_translator.TOSCATranslator(tosca,

@ -84,7 +84,7 @@ class TOSCAToHOT(object):
self.fields['template'] = self.heat_template_yaml
if is_tosca_format:
self._handle_scaling(vnfd_dict)
self._handle_policies(vnfd_dict)
if self.monitoring_dict:
self.vnf['attributes']['monitoring_policy'] = jsonutils.dumps(
self.monitoring_dict)
@ -124,30 +124,23 @@ class TOSCAToHOT(object):
return dev_attrs
@log.log
def _handle_scaling(self, vnfd_dict):
def _handle_policies(self, vnfd_dict):
vnf = self.vnf
(is_scaling_needed, scaling_group_names,
main_dict) = self._generate_hot_scaling(
vnfd_dict['topology_template'], 'scaling.yaml')
(is_enabled_alarm, alarm_resource, sub_heat_tpl_yaml) =\
(is_enabled_alarm, alarm_resource, heat_tpl_yaml) =\
self._generate_hot_alarm_resource(vnfd_dict['topology_template'])
if is_enabled_alarm and not is_scaling_needed:
self.fields['template'] = self.heat_template_yaml
self.fields['template'] = heat_tpl_yaml
if is_scaling_needed:
if is_enabled_alarm:
main_dict['resources'].update(alarm_resource)
main_yaml = yaml.dump(main_dict)
self.fields['template'] = main_yaml
if is_enabled_alarm:
self.fields['files'] = {
'scaling.yaml': sub_heat_tpl_yaml
}
else:
self.fields['files'] = {
'scaling.yaml': self.heat_template_yaml
}
self.fields['files'] = {'scaling.yaml': self.heat_template_yaml}
vnf['attributes']['heat_template'] = main_yaml
# TODO(kanagaraj-manickam) when multiple groups are
# supported, make this scaling atribute as
@ -309,6 +302,7 @@ class TOSCAToHOT(object):
LOG.debug("tosca-parser error: %s", str(e))
raise vnfm.ToscaParserFailed(error_msg_details=str(e))
metadata = toscautils.get_vdu_metadata(tosca)
monitoring_dict = toscautils.get_vdu_monitoring(tosca)
mgmt_ports = toscautils.get_mgmt_ports(tosca)
res_tpl = toscautils.get_resources_dict(tosca,
@ -322,10 +316,12 @@ class TOSCAToHOT(object):
LOG.debug("heat-translator error: %s", str(e))
raise vnfm.HeatTranslatorFailed(error_msg_details=str(e))
heat_template_yaml = toscautils.post_process_heat_template(
heat_template_yaml, mgmt_ports, res_tpl, self.unsupported_props)
heat_template_yaml, mgmt_ports, metadata,
res_tpl, self.unsupported_props)
self.heat_template_yaml = heat_template_yaml
self.monitoring_dict = monitoring_dict
self.metadata = metadata
@log.log
def _generate_hot_from_legacy(self, vnfd_dict, dev_attrs):
@ -514,57 +510,55 @@ class TOSCAToHOT(object):
alarm_resource = dict()
heat_tpl = self.heat_template_yaml
heat_dict = yamlparser.simple_ordered_parse(heat_tpl)
sub_heat_dict = copy.deepcopy(heat_dict)
is_enabled_alarm = False
if 'policies' in topology_tpl_dict:
for policy_dict in topology_tpl_dict['policies']:
name, policy_tpl_dict = list(policy_dict.items())[0]
if policy_tpl_dict['type'] == ALARMING_POLICY:
# need to parse triggers here: scaling in/out, respawn,...
if policy_tpl_dict['type'] == \
'tosca.policies.tacker.Alarming':
is_enabled_alarm = True
alarm_resource[name], sub_heat_dict =\
self._convert_to_heat_monitoring_resource(policy_dict,
self.vnf, sub_heat_dict, topology_tpl_dict)
heat_dict['resources'].update(alarm_resource)
break
self.heat_template_yaml = yaml.dump(heat_dict)
sub_heat_tpl_yaml = yaml.dump(sub_heat_dict)
return (is_enabled_alarm, alarm_resource, sub_heat_tpl_yaml)
@log.log
def _convert_to_heat_monitoring_resource(self, mon_policy, vnf,
sub_heat_dict, topology_tpl_dict):
triggers = policy_tpl_dict['triggers']
for trigger_name, trigger_dict in triggers.items():
alarm_resource[trigger_name] =\
self._convert_to_heat_monitoring_resource({
trigger_name: trigger_dict}, self.vnf)
heat_dict['resources'].update(alarm_resource)
heat_tpl_yaml = yaml.dump(heat_dict)
return (is_enabled_alarm,
alarm_resource,
heat_tpl_yaml
)
def _convert_to_heat_monitoring_resource(self, mon_policy, vnf):
mon_policy_hot = {'type': 'OS::Aodh::Alarm'}
mon_policy_hot['properties'] = self._convert_to_heat_monitoring_prop(
mon_policy, vnf)
if 'policies' in topology_tpl_dict:
for policies in topology_tpl_dict['policies']:
policy_name, policy_dt = list(policies.items())[0]
if policy_dt['type'] == SCALING_POLICY:
# Fixed metadata. it will be fixed
# once targets are supported
metadata_dict = dict()
metadata_dict['metering.vnf_id'] = vnf['id']
sub_heat_dict['resources']['VDU1']['properties']['metadata'] =\
metadata_dict
matching_metadata_dict = dict()
matching_metadata_dict['metadata.user_metadata.vnf_id'] =\
vnf['id']
mon_policy_hot['properties']['matching_metadata'] =\
matching_metadata_dict
break
return mon_policy_hot, sub_heat_dict
mon_policy_hot['properties'] = \
self._convert_to_heat_monitoring_prop(mon_policy, vnf)
return mon_policy_hot
@log.log
def _convert_to_heat_monitoring_prop(self, mon_policy, vnf):
name, mon_policy_dict = list(mon_policy.items())[0]
tpl_trigger_name = mon_policy_dict['triggers']['resize_compute']
tpl_condition = tpl_trigger_name['condition']
properties = {}
properties['meter_name'] = tpl_trigger_name['metrics']
properties['comparison_operator'] =\
metadata = self.metadata
trigger_name, trigger_dict = list(mon_policy.items())[0]
tpl_condition = trigger_dict['condition']
properties = dict()
if not (trigger_dict.get('metadata') and metadata):
raise vnfm.MetadataNotMatched()
matching_metadata_dict = dict()
properties['meter_name'] = trigger_dict['metrics']
is_matched = False
for vdu_name, metadata_dict in metadata['vdus'].items():
if trigger_dict['metadata'] ==\
metadata_dict['metering.vnf']:
is_matched = True
if not is_matched:
raise vnfm.MetadataNotMatched()
matching_metadata_dict['metadata.user_metadata.vnf'] =\
trigger_dict['metadata']
properties['matching_metadata'] = \
matching_metadata_dict
properties['comparison_operator'] = \
tpl_condition['comparison_operator']
properties['period'] = tpl_condition['period']
properties['evaluation_periods'] = tpl_condition['evaluations']
@ -572,8 +566,9 @@ class TOSCAToHOT(object):
properties['description'] = tpl_condition['constraint']
properties['threshold'] = tpl_condition['threshold']
# alarm url process here
alarm_url = str(vnf['attributes'].get('alarm_url'))
alarm_url = vnf['attributes'].get(trigger_name)
if alarm_url:
alarm_url = str(alarm_url)
LOG.debug('Alarm url in heat %s', alarm_url)
properties['alarm_actions'] = [alarm_url]
return properties

@ -215,43 +215,59 @@ class VNFAlarmMonitor(object):
'tacker.tacker.alarm_monitor.drivers',
cfg.CONF.tacker.alarm_monitor_driver)
def update_vnf_with_alarm(self, vnf, policy_name, policy_dict):
params = dict()
params['vnf_id'] = vnf['id']
params['mon_policy_name'] = policy_name
driver = policy_dict['triggers']['resize_compute'][
'event_type']['implementation']
policy_action = policy_dict['triggers']['resize_compute'].get('action')
if not policy_action:
_log_monitor_events(t_context.get_admin_context(),
vnf,
"Alarm not set: policy action missing")
return
alarm_action_name = policy_action['resize_compute'].get('action_name')
if not alarm_action_name:
_log_monitor_events(t_context.get_admin_context(),
vnf,
"Alarm not set: alarm action name missing")
return
params['mon_policy_action'] = alarm_action_name