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
This commit is contained in:
doantungbk 2016-10-05 07:51:17 -07:00
parent a1dd7fd73d
commit 0eafa5b1bf
26 changed files with 1007 additions and 257 deletions

View File

@ -44,20 +44,81 @@ described firstly like other TOSCA templates in Tacker.
evaluations: 1 evaluations: 1
method: avg method: avg
comparison_operator: gt comparison_operator: gt
action: actions: [respawn]
resize_compute:
action_name: respawn
Alarm framework already supported the some default backend actions like 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. 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 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 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 .. code-block:: yaml
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: policies:
- SP1: - SP1:
type: tosca.policies.tacker.Scaling type: tosca.policies.tacker.Scaling
@ -67,12 +128,12 @@ alarming monitoring and auto-scaling was also supported by Alarm monitor in Tack
min_instances: 1 min_instances: 1
max_instances: 3 max_instances: 3
default_instances: 2 default_instances: 2
targets: [VDU1] targets: [VDU1,VDU2]
- vdu1_cpu_usage_monitoring_policy: - vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming type: tosca.policies.tacker.Alarming
triggers: triggers:
resize_compute: vdu_hcpu_usage_scaling_out:
event_type: event_type:
type: tosca.events.resource.utilization type: tosca.events.resource.utilization
implementation: ceilometer implementation: ceilometer
@ -84,9 +145,28 @@ alarming monitoring and auto-scaling was also supported by Alarm monitor in Tack
evaluations: 1 evaluations: 1
method: avg method: avg
comparison_operator: gt comparison_operator: gt
action: metadata: SG1
resize_compute: actions: [SP1]
action_name: 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 How to setup environment
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
@ -112,45 +192,47 @@ is successfully passed to Ceilometer, Tacker users could use CLI:
.. code-block:: console .. code-block:: console
$ceilometer alarm-list $aodh alarm list
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+------------+-------------------------------------+------------------+ +--------------------------------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+
| Alarm ID | Name | State | Severity | Enabled | Continuous | Alarm condition | Time constraints | | alarm_id | type | name | state | severity | enabled |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+------------+-------------------------------------+------------------+ +--------------------------------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------+-------------------+----------+---------+
| 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 | | 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 .. code-block:: console
$ ceilometer alarm-show 35a80852-e24f-46ed-bd34-e2f831d00172 $aodh alarm show 6f2336b9-e0a2-4e33-88be-bc036192b42b
+---------------------------+--------------------------------------------------------------------------+ +---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
| Property | Value | | Field | Value |
+---------------------------+--------------------------------------------------------------------------+ +---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
| alarm_actions | ["http://pinedcn:9890/v1.0/vnfs/d4900104-6257-4084-8506-9fa6895d1294/vdu | | alarm_actions | [u'http://pinedcn:9890/v1.0/vnfs/a0f60b00-ad3d-4769-92ef-e8d9518da2c8/vdu_lcpu_scaling_in/SP1-in/yl7kh5qd'] |
| | 1_cpu_usage_monitoring_policy/SP1/i42kd018"] | | alarm_id | 6f2336b9-e0a2-4e33-88be-bc036192b42b |
| alarm_id | f6a89242-d849-4a1a-9eb5-de4c0730252f | | comparison_operator | lt |
| comparison_operator | gt | | description | utilization less_than 10% |
| description | utilization greater_than 50% |
| enabled | True | | enabled | True |
| evaluation_periods | 1 | | evaluation_periods | 1 |
| exclude_outliers | False | | exclude_outliers | False |
| insufficient_data_actions | None | | insufficient_data_actions | None |
| meter_name | cpu_util | | meter_name | cpu_util |
| name | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-d4900104-6257-40 | | name | tacker.vnfm.infra_drivers.openstack.openstack_OpenStack-a0f60b00-ad3d-4769-92ef-e8d9518da2c8-vdu_lcpu_scaling_in-smgctfnc3ql5 |
| | 84-8506-9fa6895d1294-vdu1_cpu_usage_monitoring_policy-7rt36gqbmuqo |
| ok_actions | None | | ok_actions | None |
| period | 65 | | period | 600 |
| project_id | abdc74442be44b9486ca5e32a980bca1 | | project_id | 3db801789c9e4b61b14ce448c9e7fb6d |
| query | metadata.user_metadata.vnf_id == d4900104-6257-4084-8506-9fa6895d1294 | | query | metadata.user_metadata.vnf_id = a0f60b00-ad3d-4769-92ef-e8d9518da2c8 |
| repeat_actions | True | | repeat_actions | True |
| severity | low | | severity | low |
| state | insufficient data | | state | insufficient data |
| state_timestamp | 2016-11-16T18:39:30.134954 |
| statistic | avg | | statistic | avg |
| threshold | 15.0 | | threshold | 10.0 |
| time_constraints | [] |
| timestamp | 2016-11-16T18:39:30.134954 |
| type | threshold | | type | threshold |
| user_id | 25a691398e534893b8627f3762712515 | | user_id | a783e8a94768484fb9a43af03c6426cb |
+---------------------------+--------------------------------------------------------------------------+ +---------------------------+-------------------------------------------------------------------------------------------------------------------------------+
How to trigger alarms: 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 .. 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 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. in the above command could be captured from "**ceilometer alarm-show** command as shown before.

View File

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

View File

@ -18,6 +18,7 @@ topology_template:
image: cirros-0.3.4-x86_64-uec image: cirros-0.3.4-x86_64-uec
mgmt_driver: noop mgmt_driver: noop
availability_zone: nova availability_zone: nova
metadata: {metering.vnf: SG1}
CP1: CP1:
type: tosca.nodes.nfv.CP.Tacker type: tosca.nodes.nfv.CP.Tacker
@ -29,6 +30,30 @@ topology_template:
node: VL1 node: VL1
- virtualBinding: - virtualBinding:
node: VDU1 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: VL1:
type: tosca.nodes.nfv.VL type: tosca.nodes.nfv.VL
@ -45,12 +70,12 @@ topology_template:
min_instances: 1 min_instances: 1
max_instances: 3 max_instances: 3
default_instances: 2 default_instances: 2
targets: [VDU1] targets: [VDU1,VDU2]
- vdu1_cpu_usage_monitoring_policy: - vdu_cpu_usage_monitoring_policy:
type: tosca.policies.tacker.Alarming type: tosca.policies.tacker.Alarming
triggers: triggers:
resize_compute: vdu_hcpu_usage_scaling_out:
event_type: event_type:
type: tosca.events.resource.utilization type: tosca.events.resource.utilization
implementation: ceilometer implementation: ceilometer
@ -62,6 +87,21 @@ topology_template:
evaluations: 1 evaluations: 1
method: avg method: avg
comparison_operator: gt comparison_operator: gt
action: metadata: SG1
resize_compute: actions: [SP1]
action_name: 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]

View File

@ -249,6 +249,10 @@ class AlarmUrlInvalid(BadRequest):
message = _("Invalid alarm url for VNF %(vnf_id)s") 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): class VnfPolicyNotFound(NotFound):
message = _("Policy %(policy)s does not exist for VNF %(vnf_id)s") message = _("Policy %(policy)s does not exist for VNF %(vnf_id)s")

View File

@ -153,6 +153,10 @@ class VNFInactive(exceptions.InvalidInput):
message = _("VNF %(vnf_id)s is not in Active state %(message)s") 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): def _validate_service_type_list(data, valid_values=None):
if not isinstance(data, list): if not isinstance(data, list):
msg = _("invalid data format for service list: '%s'") % data msg = _("invalid data format for service list: '%s'") % data

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # 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_CREATE_TIMEOUT = 300
VNF_CIRROS_DELETE_TIMEOUT = 300 VNF_CIRROS_DELETE_TIMEOUT = 300
VNF_CIRROS_DEAD_TIMEOUT = 250 VNF_CIRROS_DEAD_TIMEOUT = 250

View File

@ -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]

View File

@ -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]

View File

@ -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')

View File

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

View File

@ -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

View File

@ -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'}

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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: ''

View File

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

View File

@ -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]

View File

@ -457,3 +457,26 @@ class TestOpenStack(base.TestCase):
'test_tosca_mac_ip.yaml', 'test_tosca_mac_ip.yaml',
'hot_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
)

View File

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

View File

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

View File

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

View File

@ -215,43 +215,59 @@ class VNFAlarmMonitor(object):
'tacker.tacker.alarm_monitor.drivers', 'tacker.tacker.alarm_monitor.drivers',
cfg.CONF.tacker.alarm_monitor_driver) cfg.CONF.tacker.alarm_monitor_driver)
def update_vnf_with_alarm(self, vnf, policy_name, policy_dict): def update_vnf_with_alarm(self, plugin, context, vnf, policy_dict):
triggers = policy_dict['triggers']
alarm_url = dict()
for trigger_name, trigger_dict in triggers.items():
params = dict() params = dict()
params['vnf_id'] = vnf['id'] params['vnf_id'] = vnf['id']
params['mon_policy_name'] = policy_name params['mon_policy_name'] = trigger_name
driver = policy_dict['triggers']['resize_compute'][ driver = trigger_dict['event_type']['implementation']
'event_type']['implementation'] policy_action_list = trigger_dict.get('actions')
policy_action = policy_dict['triggers']['resize_compute'].get('action') if len(policy_action_list) == 0:
if not policy_action:
_log_monitor_events(t_context.get_admin_context(), _log_monitor_events(t_context.get_admin_context(),
vnf, vnf,
"Alarm not set: policy action missing") "Alarm not set: policy action missing")
return return
alarm_action_name = policy_action['resize_compute'].get('action_name') # Other backend policies with the construct (policy, action)
if not alarm_action_name: # ex: (SP1, in), (SP1, out)
_log_monitor_events(t_context.get_admin_context(),
vnf, def _refactor_backend_policy(bk_policy_name, bk_action_name):
"Alarm not set: alarm action name missing") policy = '%(policy_name)s-%(action_name)s' % {
return 'policy_name': bk_policy_name,
params['mon_policy_action'] = alarm_action_name 'action_name': bk_action_name}
alarm_url = self.call_alarm_url(driver, vnf, params) return policy
for policy_action in policy_action_list:
filters = {'name': policy_action}
bkend_policies =\
plugin.get_vnf_policies(context, vnf['id'], filters)
if bkend_policies:
bkend_policy = bkend_policies[0]
if bkend_policy['type'] == constants.POLICY_SCALING:
cp = trigger_dict['condition'].\
get('comparison_operator')
scaling_type = 'out' if cp == 'gt' else 'in'
policy_action = _refactor_backend_policy(policy_action,
scaling_type)
params['mon_policy_action'] = policy_action
alarm_url[trigger_name] =\
self.call_alarm_url(driver, vnf, params)
details = "Alarm URL set successfully: %s" % alarm_url details = "Alarm URL set successfully: %s" % alarm_url
_log_monitor_events(t_context.get_admin_context(), _log_monitor_events(t_context.get_admin_context(),
vnf, vnf,
details) details)
return alarm_url return alarm_url
# vnf['attribute']['alarm_url'] = alarm_url ---> create
# by plugin or vm_db
def process_alarm_for_vnf(self, policy): def process_alarm_for_vnf(self, vnf, trigger):
'''call in plugin''' '''call in plugin'''
vnf = policy['vnf'] params = trigger['params']
params = policy['params'] mon_prop = trigger['trigger']
mon_prop = policy['properties']
alarm_dict = dict() alarm_dict = dict()
alarm_dict['alarm_id'] = params['data'].get('alarm_id') alarm_dict['alarm_id'] = params['data'].get('alarm_id')
alarm_dict['status'] = params['data'].get('current') alarm_dict['status'] = params['data'].get('current')
driver = mon_prop['resize_compute']['event_type']['implementation'] trigger_name, trigger_dict = list(mon_prop.items())[0]
driver = trigger_dict['event_type']['implementation']
return self.process_alarm(driver, vnf, alarm_dict) return self.process_alarm(driver, vnf, alarm_dict)
def _invoke(self, driver, **kwargs): def _invoke(self, driver, **kwargs):
@ -382,9 +398,9 @@ class ActionRespawnHeat(ActionPolicy):
plugin.add_vnf_to_monitor(updated_vnf, vim_res['vim_type']) plugin.add_vnf_to_monitor(updated_vnf, vim_res['vim_type'])
LOG.debug(_("VNF %s added to monitor thread"), updated_vnf[ LOG.debug(_("VNF %s added to monitor thread"), updated_vnf[
'id']) 'id'])
if vnf_dict['attributes'].get('alarm_url'): if vnf_dict['attributes'].get('alarming_policy'):
_delete_heat_stack(vim_res['vim_auth']) _delete_heat_stack(vim_res['vim_auth'])
vnf_dict['attributes'].pop('alarm_url') vnf_dict['attributes'].pop('alarming_policy')
_respin_vnf() _respin_vnf()

View File

@ -249,17 +249,19 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
LOG.debug('hosting_vnf: %s', hosting_vnf) LOG.debug('hosting_vnf: %s', hosting_vnf)
self._vnf_monitor.add_hosting_vnf(hosting_vnf) self._vnf_monitor.add_hosting_vnf(hosting_vnf)
def add_alarm_url_to_vnf(self, vnf_dict): def add_alarm_url_to_vnf(self, context, vnf_dict):
vnfd_yaml = vnf_dict['vnfd']['attributes'].get('vnfd', '') vnfd_yaml = vnf_dict['vnfd']['attributes'].get('vnfd', '')
vnfd_dict = yaml.load(vnfd_yaml) vnfd_dict = yaml.load(vnfd_yaml)
if vnfd_dict and vnfd_dict.get('tosca_definitions_version'): if vnfd_dict and vnfd_dict.get('tosca_definitions_version'):
polices = vnfd_dict['topology_template'].get('policies', []) polices = vnfd_dict['topology_template'].get('policies', [])
for policy_dict in polices: for policy_dict in polices:
name, policy = policy_dict.items()[0] name, policy = list(policy_dict.items())[0]
if policy['type'] in constants.POLICY_ALARMING: if policy['type'] in constants.POLICY_ALARMING:
alarm_url = self._vnf_alarm_monitor.update_vnf_with_alarm( alarm_url =\
vnf_dict, name, policy) self._vnf_alarm_monitor.update_vnf_with_alarm(
vnf_dict['attributes']['alarm_url'] = alarm_url self, context, vnf_dict, policy)
vnf_dict['attributes']['alarming_policy'] = vnf_dict['id']
vnf_dict['attributes'].update(alarm_url)
break break
def config_vnf(self, context, vnf_dict): def config_vnf(self, context, vnf_dict):
@ -343,7 +345,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
vnf_id = vnf_dict['id'] vnf_id = vnf_dict['id']
LOG.debug(_('vnf_dict %s'), vnf_dict) LOG.debug(_('vnf_dict %s'), vnf_dict)
self.mgmt_create_pre(context, vnf_dict) self.mgmt_create_pre(context, vnf_dict)
self.add_alarm_url_to_vnf(vnf_dict) self.add_alarm_url_to_vnf(context, vnf_dict)
try: try:
instance_id = self._vnf_manager.invoke( instance_id = self._vnf_manager.invoke(
driver_name, 'create', plugin=self, driver_name, 'create', plugin=self,
@ -683,9 +685,11 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
policy_list.append(p) policy_list.append(p)
# Check for filters # Check for filters
if filters.get('name'): if filters.get('name') or filters.get('type'):
if name == filters.get('name'): if name == filters.get('name'):
_add(policy) _add(policy)
if policy['type'] == filters.get('type'):
_add(policy)
break break
else: else:
continue continue
@ -714,38 +718,70 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
return scale['scale'] return scale['scale']
def _validate_alarming_policy(self, context, policy): def get_vnf_policy_by_type(self, context, vnf_id, policy_type=None, fields=None): # noqa
vnf_id = policy['vnf']['id'] policies = self.get_vnf_policies(context,
# validate policy type vnf_id,
type = policy['type'] filters={'type': policy_type})
if type not in constants.POLICY_ALARMING: if policies:
raise exceptions.VnfPolicyTypeInvalid( return policies[0]
type=type,
valid_types=constants.POLICY_ALARMING, raise exceptions.VnfPolicyTypeInvalid(type=constants.POLICY_ALARMING,
policy=policy['id'] vnf_id=vnf_id)
)
def _validate_alarming_policy(self, context, vnf_id, trigger):
# validate alarm status # validate alarm status
if not self._vnf_alarm_monitor.process_alarm_for_vnf(policy): if not self._vnf_alarm_monitor.process_alarm_for_vnf(vnf_id, trigger):
raise exceptions.AlarmUrlInvalid(vnf_id=vnf_id) raise exceptions.AlarmUrlInvalid(vnf_id=vnf_id)
# validate policy action
action = policy['action_name']
policy_ = None policy_ = None
action_ = None
# validate policy action. if action is composite, split it.
# ex: SP1-in, SP1-out
action = trigger['action_name']
sp_action = action.split('-')
if len(sp_action) == 2:
bk_policy_name = sp_action[0]
bk_policy_action = sp_action[1]
policies_ = self.get_vnf_policies(context, vnf_id,
filters={'name': bk_policy_name})
if policies_:
policy_ = policies_[0]
action_ = bk_policy_action
if not policy_:
if action not in constants.DEFAULT_ALARM_ACTIONS: if action not in constants.DEFAULT_ALARM_ACTIONS:
policy_ = self.get_vnf_policy(context, action, vnf_id) policy_ = self.get_vnf_policy(context, action, vnf_id)
if not policy_: LOG.debug(_("Trigger %s is validated successfully") % trigger)
raise exceptions.VnfPolicyNotFound( return policy_, action_
vnf_id=action,
policy=policy['id']
)
LOG.debug(_("Policy %s is validated successfully") % policy)
return policy_
# validate url # validate url
def _handle_vnf_monitoring(self, context, policy): def _get_vnf_triggers(self, context, vnf_id, filters=None, fields=None):
vnf_dict = policy['vnf'] policy = self.get_vnf_policy_by_type(
if policy['action_name'] in constants.DEFAULT_ALARM_ACTIONS: context, vnf_id, policy_type=constants.POLICY_ALARMING)
action = policy['action_name'] triggers = policy['properties']
vnf_trigger = dict()
for trigger_name, trigger_dict in triggers.items():
if trigger_name == filters.get('name'):
vnf_trigger['trigger'] = {trigger_name: trigger_dict}
vnf_trigger['vnf'] = policy['vnf']
break
return vnf_trigger
def get_vnf_trigger(self, context, vnf_id, trigger_name):
trigger = self._get_vnf_triggers(
context, vnf_id, filters={'name': trigger_name})
if not trigger:
raise exceptions.TriggerNotFound(
trigger_name=trigger_name,
vnf_id=vnf_id
)
return trigger
def _handle_vnf_monitoring(self, context, trigger):
vnf_dict = trigger['vnf']
if trigger['action_name'] in constants.DEFAULT_ALARM_ACTIONS:
action = trigger['action_name']
LOG.debug(_('vnf for monitoring: %s'), vnf_dict) LOG.debug(_('vnf for monitoring: %s'), vnf_dict)
infra_driver, vim_auth = self._get_infra_driver(context, vnf_dict) infra_driver, vim_auth = self._get_infra_driver(context, vnf_dict)
action_cls = monitor.ActionPolicy.get_policy(action, action_cls = monitor.ActionPolicy.get_policy(action,
@ -753,11 +789,9 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
if action_cls: if action_cls:
action_cls.execute_action(self, vnf_dict) action_cls.execute_action(self, vnf_dict)
if policy.get('bckend_policy'): if trigger.get('bckend_policy'):
bckend_policy = policy['bckend_policy'] bckend_policy = trigger['bckend_policy']
bckend_policy_type = bckend_policy['type'] bckend_policy_type = bckend_policy['type']
cp = policy['properties']['resize_compute']['condition'].\
get('comparison_operator')
if bckend_policy_type == constants.POLICY_SCALING: if bckend_policy_type == constants.POLICY_SCALING:
if vnf_dict['status'] != constants.ACTIVE: if vnf_dict['status'] != constants.ACTIVE:
LOG.info(context, vnf_dict, LOG.info(context, vnf_dict,
@ -766,7 +800,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
action = 'scaling' action = 'scaling'
scale = {} scale = {}
scale.setdefault('scale', {}) scale.setdefault('scale', {})
scale['scale']['type'] = 'out' if cp == 'gt' else 'in' scale['scale']['type'] = trigger['bckend_action']
scale['scale']['policy'] = bckend_policy['name'] scale['scale']['policy'] = bckend_policy['name']
infra_driver, vim_auth = self._get_infra_driver(context, infra_driver, vim_auth = self._get_infra_driver(context,
vnf_dict) vnf_dict)
@ -777,22 +811,16 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
def create_vnf_trigger( def create_vnf_trigger(
self, context, vnf_id, trigger): self, context, vnf_id, trigger):
# Verified API: pending trigger_ = self.get_vnf_trigger(
# Need to use: _make_policy_dict, get_vnf_policies, get_vnf_policy context, vnf_id, trigger['trigger']['policy_name'])
# action: scaling, refer to template to find specific scaling policy trigger_.update({'action_name': trigger['trigger']['action_name']})
# we can extend in future to support other policies trigger_.update({'params': trigger['trigger']['params']})
# Monitoring policy should be describe in heat_template_yaml. bk_policy, bk_action = self._validate_alarming_policy(
# Create first context, vnf_id, trigger_)
policy_ = self.get_vnf_policy(context,
trigger['trigger']['policy_name'],
vnf_id)
policy_.update({'action_name': trigger['trigger']['action_name']})
policy_.update({'params': trigger['trigger']['params']})
bk_policy = self._validate_alarming_policy(context, policy_)
if bk_policy: if bk_policy:
policy_.update({'bckend_policy': bk_policy}) trigger_.update({'bckend_policy': bk_policy,
self._handle_vnf_monitoring(context, policy_) 'bckend_action': bk_action})
self._handle_vnf_monitoring(context, trigger_)
return trigger['trigger'] return trigger['trigger']
def get_vnf_resources(self, context, vnf_id, fields=None, filters=None): def get_vnf_resources(self, context, vnf_id, fields=None, filters=None):

View File

@ -62,7 +62,7 @@ FLAVOR_EXTRA_SPECS_LIST = ('cpu_allocation',
delpropmap = {TACKERVDU: ('mgmt_driver', 'config', 'service_type', delpropmap = {TACKERVDU: ('mgmt_driver', 'config', 'service_type',
'placement_policy', 'monitoring_policy', 'placement_policy', 'monitoring_policy',
'failure_policy'), 'metadata', 'failure_policy'),
TACKERCP: ('management',)} TACKERCP: ('management',)}
convert_prop = {TACKERCP: {'anti_spoofing_protection': convert_prop = {TACKERCP: {'anti_spoofing_protection':
@ -117,6 +117,19 @@ def get_vdu_monitoring(template):
return monitoring_dict return monitoring_dict
@log.log
def get_vdu_metadata(template):
metadata = dict()
metadata.setdefault('vdus', {})
for nt in template.nodetemplates:
if nt.type_definition.is_derived_from(TACKERVDU):
metadata_dict = nt.get_property_value('metadata') or None
if metadata_dict:
metadata['vdus'][nt.name] = {}
metadata['vdus'][nt.name].update(metadata_dict)
return metadata
@log.log @log.log
def get_mgmt_ports(tosca): def get_mgmt_ports(tosca):
mgmt_ports = {} mgmt_ports = {}
@ -177,8 +190,8 @@ def convert_unsupported_res_prop(heat_dict, unsupported_res_prop):
@log.log @log.log
def post_process_heat_template(heat_tpl, mgmt_ports, res_tpl, def post_process_heat_template(heat_tpl, mgmt_ports, metadata,
unsupported_res_prop=None): res_tpl, unsupported_res_prop=None):
# #
# TODO(bobh) - remove when heat-translator can support literal strings. # TODO(bobh) - remove when heat-translator can support literal strings.
# #
@ -200,6 +213,11 @@ def post_process_heat_template(heat_tpl, mgmt_ports, res_tpl,
else: else:
heat_dict['outputs'] = output heat_dict['outputs'] = output
LOG.debug(_('Added output for %s'), outputname) LOG.debug(_('Added output for %s'), outputname)
if metadata:
for vdu_name, metadata_dict in metadata['vdus'].items():
heat_dict['resources'][vdu_name]['properties']['metadata'] =\
metadata_dict
add_resources_tpl(heat_dict, res_tpl) add_resources_tpl(heat_dict, res_tpl)
if unsupported_res_prop: if unsupported_res_prop:
convert_unsupported_res_prop(heat_dict, unsupported_res_prop) convert_unsupported_res_prop(heat_dict, unsupported_res_prop)