Coverage for osm_policy_module/tests/integration/test_policy_agent.py: 98%
124 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-07 08:03 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-07 08:03 +0000
1# -*- coding: utf-8 -*-
3# Copyright 2018 Whitestack, LLC
4# *************************************************************
6# This file is part of OSM Monitoring module
7# All Rights Reserved to Whitestack, LLC
9# Licensed under the Apache License, Version 2.0 (the "License"); you may
10# not use this file except in compliance with the License. You may obtain
11# a copy of the License at
13# http://www.apache.org/licenses/LICENSE-2.0
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18# License for the specific language governing permissions and limitations
19# under the License.
21# For those usages not covered by the Apache License, Version 2.0 please
22# contact: bdiaz@whitestack.com or glavado@whitestack.com
23##
24import asyncio
25import logging
26import os
27import sys
28import unittest
29import uuid
30from unittest.mock import patch, Mock
32from aiokafka import AIOKafkaProducer
33from osm_common.dbmongo import DbMongo
34from playhouse.db_url import connect
36from osm_policy_module.common.common_db_client import CommonDbClient
37from osm_policy_module.common.mon_client import MonClient
38from osm_policy_module.core import database
39from osm_policy_module.core.agent import PolicyModuleAgent
40from osm_policy_module.core.config import Config
41from osm_policy_module.core.database import (
42 ScalingGroup,
43 ScalingAlarm,
44 ScalingPolicy,
45 ScalingCriteria,
46 VnfAlarm,
47 AlarmAction,
48 HealingAction,
49)
51log = logging.getLogger()
52log.level = logging.INFO
53stream_handler = logging.StreamHandler(sys.stdout)
54log.addHandler(stream_handler)
56nsr_record_mock = {
57 "_id": "87776f33-b67c-417a-8119-cb08e4098951",
58 "crete-time": 1535392482.0044956,
59 "operational-status": "running",
60 "ssh-authorized-key": None,
61 "name-ref": "cirros_ns",
62 "nsd": {
63 "_id": "d7c8bd3c-eb39-4514-8847-19f01345524f",
64 "_admin": {
65 "created": 1535392246.499733,
66 "userDefinedData": {},
67 "usageSate": "NOT_IN_USE",
68 "storage": {
69 "zipfile": "package.tar.gz",
70 "fs": "local",
71 "path": "/app/storage/",
72 "folder": "d7c8bd3c-eb39-4514-8847-19f01345524f",
73 "pkg-dir": "cirros_nsd",
74 "descriptor": "cirros_nsd/cirros_vdu_scaling_nsd.yaml",
75 },
76 "onboardingState": "ONBOARDED",
77 "modified": 1535392246.499733,
78 "projects_read": ["admin"],
79 "operationalState": "ENABLED",
80 "projects_write": ["admin"],
81 },
82 "id": "cirros_vdu_scaling_ns",
83 "name": "cirros_vdu_scaling_ns",
84 "description": "Simple NS example with a cirros_vdu_scaling_vnf",
85 "designer": "OSM",
86 "version": "1.0",
87 "vnfd-id": ["cirros_vdu_scaling_vnf"],
88 "df": [
89 {
90 "id": "default-df",
91 "vnf-profile": [
92 {
93 "id": "1",
94 "vnfd-id": "cirros_vdu_scaling_vnf",
95 "virtual-link-connectivity": [
96 {
97 "virtual-link-profile-id": "cirros_nsd_vld1",
98 "constituent-cpd-id": [
99 {
100 "constituent-base-element-id": "1",
101 "constituent-cpd-id": "eth0-ext",
102 }
103 ],
104 }
105 ],
106 },
107 {
108 "id": "2",
109 "vnfd-id": "cirros_vdu_scaling_vnf",
110 "virtual-link-connectivity": [
111 {
112 "virtual-link-profile-id": "cirros_nsd_vld1",
113 "constituent-cpd-id": [
114 {
115 "constituent-base-element-id": "2",
116 "constituent-cpd-id": "eth0-ext",
117 }
118 ],
119 }
120 ],
121 },
122 ],
123 }
124 ],
125 "virtual-link-desc": [{"id": "cirros_nsd_vld1", "mgmt-network": "true"}],
126 },
127 "id": "87776f33-b67c-417a-8119-cb08e4098951",
128 "config-status": "configured",
129 "operational-events": [],
130 "_admin": {
131 "created": 1535392482.0084584,
132 "projects_read": ["admin"],
133 "nsState": "INSTANTIATED",
134 "modified": 1535392482.0084584,
135 "projects_write": ["admin"],
136 "deployed": {
137 "RO": {
138 "vnfd_id": {
139 "cirros_vdu_scaling_vnf": "7445e347-fe2f-431a-abc2-8b9be3d093c6"
140 },
141 "nsd_id": "92c56cf0-f8fa-488c-9afb-9f3d78ae6bbb",
142 "nsr_id": "637e12cd-c201-4c44-8ebd-70fb57a4dcee",
143 "nsr_status": "BUILD",
144 }
145 },
146 },
147 "nsd-ref": "cirros_vdu_scaling_ns",
148 "name": "cirros_ns",
149 "resource-orchestrator": "osmopenmano",
150 "instantiate_params": {
151 "nsDescription": "default description",
152 "nsdId": "d7c8bd3c-eb39-4514-8847-19f01345524f",
153 "nsr_id": "87776f33-b67c-417a-8119-cb08e4098951",
154 "nsName": "cirros_ns",
155 "vimAccountId": "be48ae31-1d46-4892-a4b4-d69abd55714b",
156 },
157 "description": "default description",
158 "constituent-vnfr-ref": [
159 "0d9d06ad-3fc2-418c-9934-465e815fafe2",
160 "3336eb44-77df-4c4f-9881-d2828d259864",
161 ],
162 "admin-status": "ENABLED",
163 "detailed-status": "done",
164 "datacenter": "be48ae31-1d46-4892-a4b4-d69abd55714b",
165 "orchestration-progress": {},
166 "short-name": "cirros_ns",
167 "ns-instance-config-ref": "87776f33-b67c-417a-8119-cb08e4098951",
168 "nsd-name-ref": "cirros_vdu_scaling_ns",
169 "admin": {"deployed": {"RO": {"nsr_status": "ACTIVE"}}},
170}
172vnfr_record_mocks = [
173 {
174 "_id": "0d9d06ad-3fc2-418c-9934-465e815fafe2",
175 "ip-address": "192.168.160.2",
176 "created-time": 1535392482.0044956,
177 "vim-account-id": "be48ae31-1d46-4892-a4b4-d69abd55714b",
178 "vdur": [
179 {
180 "interfaces": [
181 {
182 "mac-address": "fa:16:3e:71:fd:b8",
183 "name": "eth0",
184 "ip-address": "192.168.160.2",
185 }
186 ],
187 "count-index": 0,
188 "status": "ACTIVE",
189 "vim-id": "63a65636-9fc8-4022-b070-980823e6266a",
190 "name": "cirros_ns-1-cirros_vnfd-VM-1",
191 "status-detailed": None,
192 "ip-address": "192.168.160.2",
193 "vdu-id-ref": "cirros_vnfd-VM",
194 }
195 ],
196 "id": "0d9d06ad-3fc2-418c-9934-465e815fafe2",
197 "vnfd-ref": "cirros_vdu_scaling_vnf",
198 "vnfd-id": "63f44c41-45ee-456b-b10d-5f08fb1796e0",
199 "_admin": {
200 "created": 1535392482.0067868,
201 "projects_read": ["admin"],
202 "modified": 1535392482.0067868,
203 "projects_write": ["admin"],
204 },
205 "nsr-id-ref": "87776f33-b67c-417a-8119-cb08e4098951",
206 "member-vnf-index-ref": "1",
207 "connection-point": [{"name": "eth0", "id": None, "connection-point-id": None}],
208 },
209 {
210 "_id": "3336eb44-77df-4c4f-9881-d2828d259864",
211 "ip-address": "192.168.160.10",
212 "created-time": 1535392482.0044956,
213 "vim-account-id": "be48ae31-1d46-4892-a4b4-d69abd55714b",
214 "vdur": [
215 {
216 "interfaces": [
217 {
218 "mac-address": "fa:16:3e:1e:76:e8",
219 "name": "eth0",
220 "ip-address": "192.168.160.10",
221 }
222 ],
223 "count-index": 0,
224 "status": "ACTIVE",
225 "vim-id": "a154b8d3-2b10-421a-a51d-4b391d9bd366",
226 "name": "cirros_ns-2-cirros_vnfd-VM-1",
227 "status-detailed": None,
228 "ip-address": "192.168.160.10",
229 "vdu-id-ref": "cirros_vnfd-VM",
230 }
231 ],
232 "id": "3336eb44-77df-4c4f-9881-d2828d259864",
233 "vnfd-ref": "cirros_vdu_scaling_vnf",
234 "vnfd-id": "63f44c41-45ee-456b-b10d-5f08fb1796e0",
235 "_admin": {
236 "created": 1535392482.0076294,
237 "projects_read": ["admin"],
238 "modified": 1535392482.0076294,
239 "projects_write": ["admin"],
240 },
241 "nsr-id-ref": "87776f33-b67c-417a-8119-cb08e4098951",
242 "member-vnf-index-ref": "2",
243 "connection-point": [{"name": "eth0", "id": None, "connection-point-id": None}],
244 },
245]
247nsd_record_mock = {
248 "id": "cirros_vdu_scaling_ns",
249 "name": "cirros_vdu_scaling_ns",
250 "description": "Simple NS example with a cirros_vdu_scaling_vnf",
251 "designer": "OSM",
252 "version": "1.0",
253 "vnfd-id": ["cirros_vdu_scaling_vnf"],
254 "df": [
255 {
256 "id": "default-df",
257 "vnf-profile": [
258 {
259 "id": "1",
260 "vnfd-id": "cirros_vdu_scaling_vnf",
261 "virtual-link-connectivity": [
262 {
263 "virtual-link-profile-id": "cirros_nsd_vld1",
264 "constituent-cpd-id": [
265 {
266 "constituent-base-element-id": "1",
267 "constituent-cpd-id": "eth0-ext",
268 }
269 ],
270 }
271 ],
272 },
273 {
274 "id": "2",
275 "vnfd-id": "cirros_vdu_scaling_vnf",
276 "virtual-link-connectivity": [
277 {
278 "virtual-link-profile-id": "cirros_nsd_vld1",
279 "constituent-cpd-id": [
280 {
281 "constituent-base-element-id": "2",
282 "constituent-cpd-id": "eth0-ext",
283 }
284 ],
285 }
286 ],
287 },
288 ],
289 }
290 ],
291 "virtual-link-desc": [{"id": "cirros_nsd_vld1", "mgmt-network": "true"}],
292}
295vnfd_record_mock = {
296 "id": "cirros_vdu_scaling_vnf",
297 "_id": "63f44c41-45ee-456b-b10d-5f08fb1796e0",
298 "product-name": "cirros_vdu_scaling_vnf",
299 "description": "Simple VNF example with a cirros and a scaling group descriptor",
300 "provider": "OSM",
301 "version": "1.0",
302 "mgmt-cp": "eth0-ext",
303 "virtual-storage-desc": [{"id": "cirros_vnfd-VM-storage", "size-of-storage": 2}],
304 "virtual-compute-desc": [
305 {
306 "id": "cirros_vnfd-VM-compute",
307 "virtual-cpu": {"num-virtual-cpu": 1},
308 "virtual-memory": {"size": 0.25},
309 }
310 ],
311 "sw-image-desc": [{"id": "cirros034", "name": "cirros034", "image": "cirros034"}],
312 "vdu": [
313 {
314 "id": "cirros_vnfd-VM",
315 "description": "cirros_vnfd-VM",
316 "name": "cirros_vnfd-VM",
317 "alarm": [
318 {
319 "value": 20.0,
320 "actions": {
321 "insufficient-data": [{"url": "localhost:9090"}],
322 "ok": [{"url": "localhost:9090"}],
323 "alarm": [{"url": "localhost:9090"}],
324 },
325 "alarm-id": "alarm-1",
326 "operation": "LT",
327 "vnf-monitoring-param-ref": "cirros_vnf_memory_util",
328 }
329 ],
330 "sw-image-desc": "cirros034",
331 "virtual-compute-desc": "cirros_vnfd-VM-compute",
332 "virtual-storage-desc": ["cirros_vnfd-VM-storage"],
333 "int-cpd": [
334 {
335 "id": "eth0-int",
336 "virtual-network-interface-requirement": [
337 {
338 "name": "eth0",
339 "virtual-interface": {
340 "bandwidth": "0",
341 "type": "VIRTIO",
342 "vpci": "0000:00:0a.0",
343 },
344 }
345 ],
346 }
347 ],
348 "monitoring-parameter": [
349 {
350 "id": "cirros_vnf_memory_util",
351 "name": "cirros_vnf_memory_util",
352 "performance-metric": "average_memory_utilization",
353 }
354 ],
355 }
356 ],
357 "df": [
358 {
359 "id": "default-df",
360 "vdu-profile": [
361 {
362 "id": "cirros_vnfd-VM",
363 "min-number-of-instances": 1,
364 "max-number-of-instances": 10,
365 "vdu-configuration-id": "cirros_vnfd-VM-vdu-configuration",
366 }
367 ],
368 "healing-aspect": [
369 {
370 "id": "cirros_vnfd-VM-autoheal",
371 "healing-policy": [
372 {
373 "vdu-id": "cirros_vnfd-VM",
374 "event-name": "heal-alarm",
375 "recovery-type": "automatic",
376 "action-on-recovery": "REDEPLOY_ONLY",
377 "cooldown-time": 180,
378 "day1": False,
379 }
380 ],
381 }
382 ],
383 "instantiation-level": [
384 {
385 "id": "default-instantiation-level",
386 "vdu-level": [
387 {"vdu-id": "cirros_vnfd-VM", "number-of-instances": 1}
388 ],
389 }
390 ],
391 "scaling-aspect": [
392 {
393 "id": "scale_cirros_vnfd-VM",
394 "name": "scale_cirros_vnfd-VM",
395 "max-scale-level": 10,
396 "scaling-policy": [
397 {
398 "name": "auto_memory_util_above_threshold",
399 "scaling-type": "automatic",
400 "cooldown-time": 60,
401 "threshold-time": 10,
402 "scaling-criteria": [
403 {
404 "name": "group1_memory_util_above_threshold",
405 "vnf-monitoring-param-ref": "cirros_vnf_memory_util",
406 "scale-out-threshold": 80,
407 "scale-out-relational-operation": "GT",
408 "scale-in-relational-operation": "LT",
409 "scale-in-threshold": 20,
410 }
411 ],
412 }
413 ],
414 "aspect-delta-details": {
415 "deltas": [
416 {
417 "id": "scale_cirros_vnfd-VM-delta",
418 "vdu-delta": [
419 {"number-of-instances": 1, "id": "cirros_vnfd-VM"}
420 ],
421 }
422 ]
423 },
424 }
425 ],
426 }
427 ],
428 "ext-cpd": [
429 {"id": "eth0-ext", "int-cpd": {"vdu-id": "cirros_vnfd-VM", "cpd": "eth0-int"}}
430 ],
431 "vdu-configuration": [
432 {
433 "juju": {"charm": "testmetrics", "proxy": True},
434 "metrics": [{"name": "users"}],
435 "id": "cirros_vnfd-VM-vdu-configuration",
436 }
437 ],
438 "_admin": {
439 "created": 1535392242.6281035,
440 "modified": 1535392242.6281035,
441 "storage": {
442 "zipfile": "package.tar.gz",
443 "pkg-dir": "cirros_vnf",
444 "path": "/app/storage/",
445 "folder": "63f44c41-45ee-456b-b10d-5f08fb1796e0",
446 "fs": "local",
447 "descriptor": "cirros_vnf/cirros_vdu_scaling_vnfd.yaml",
448 },
449 "usageSate": "NOT_IN_USE",
450 "onboardingState": "ONBOARDED",
451 "userDefinedData": {},
452 "projects_read": ["admin"],
453 "operationalState": "ENABLED",
454 "projects_write": ["admin"],
455 },
456}
458MODELS = [
459 ScalingGroup,
460 ScalingPolicy,
461 ScalingCriteria,
462 ScalingAlarm,
463 VnfAlarm,
464 AlarmAction,
465 HealingAction,
466]
469class PolicyModuleAgentTest(unittest.TestCase):
470 def setUp(self):
471 super()
472 database.db.initialize(connect("sqlite:///test_db.sqlite"))
473 database.db.bind(MODELS)
474 database.db.connect()
475 database.db.drop_tables(MODELS)
476 database.db.create_tables(MODELS)
477 database.db.close()
478 self.loop = asyncio.new_event_loop()
480 def tearDown(self):
481 super()
482 os.remove("test_db.sqlite")
484 @patch.object(DbMongo, "db_connect", Mock())
485 @patch.object(AIOKafkaProducer, "__init__")
486 @patch.object(MonClient, "create_alarm")
487 @patch.object(CommonDbClient, "get_vnfd")
488 @patch.object(CommonDbClient, "get_nsr")
489 @patch.object(CommonDbClient, "get_vnfr")
490 def test_configure_scaling_groups(
491 self, get_vnfr, get_nsr, get_vnfd, create_alarm, kafka_producer_init
492 ):
493 def _test_configure_scaling_groups_get_vnfr(*args, **kwargs):
494 if "1" in args[1]:
495 return vnfr_record_mocks[0]
496 if "2" in args[1]:
497 return vnfr_record_mocks[1]
499 def assert_not_called_with(*args, **kwargs):
500 try:
501 create_alarm.assert_called_with(*args, **kwargs)
502 except AssertionError:
503 return
504 raise AssertionError("Expected to not have been called.")
506 async def _test_configure_scaling_groups_create_alarm(*args, **kwargs):
507 return uuid.uuid4()
509 kafka_producer_init.return_value = None
510 get_vnfr.side_effect = _test_configure_scaling_groups_get_vnfr
511 get_nsr.return_value = nsr_record_mock
512 get_vnfd.return_value = vnfd_record_mock
513 create_alarm.side_effect = _test_configure_scaling_groups_create_alarm
514 create_alarm.assert_not_called_with = assert_not_called_with
515 config = Config()
516 agent = PolicyModuleAgent(config)
517 self.loop.run_until_complete(
518 agent.autoscaling_service.configure_scaling_groups("test_nsr_id")
519 )
520 create_alarm.assert_any_call(
521 metric_name="average_memory_utilization",
522 ns_id="test_nsr_id",
523 operation="GT",
524 threshold=80,
525 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
526 vnf_member_index="1",
527 action="scale_out",
528 vnfr=vnfr_record_mocks[0],
529 vnfd=vnfd_record_mock,
530 )
531 create_alarm.assert_not_called_with(
532 metric_name="average_memory_utilization",
533 ns_id="test_nsr_id",
534 operation="LT",
535 threshold=20,
536 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
537 vnf_member_index="1",
538 action="scale_out",
539 vnfr=vnfr_record_mocks[0],
540 vnfd=vnfd_record_mock,
541 )
542 create_alarm.assert_any_call(
543 metric_name="average_memory_utilization",
544 ns_id="test_nsr_id",
545 operation="GT",
546 threshold=80,
547 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
548 vnf_member_index="2",
549 action="scale_out",
550 vnfr=vnfr_record_mocks[1],
551 vnfd=vnfd_record_mock,
552 )
553 create_alarm.assert_not_called_with(
554 metric_name="average_memory_utilization",
555 ns_id="test_nsr_id",
556 operation="LT",
557 threshold=20,
558 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
559 vnf_member_index="2",
560 action="scale_out",
561 vnfr=vnfr_record_mocks[1],
562 vnfd=vnfd_record_mock,
563 )
564 scaling_record = ScalingGroup.get()
565 self.assertEqual(scaling_record.name, "scale_cirros_vnfd-VM")
566 self.assertEqual(scaling_record.nsr_id, "test_nsr_id")
568 @patch.object(DbMongo, "db_connect", Mock())
569 @patch.object(AIOKafkaProducer, "__init__")
570 @patch.object(MonClient, "create_alarm")
571 @patch.object(CommonDbClient, "get_vnfd")
572 @patch.object(CommonDbClient, "get_nsr")
573 @patch.object(CommonDbClient, "get_vnfr")
574 def test_configure_vnf_alarms(
575 self, get_vnfr, get_nsr, get_vnfd, create_alarm, kafka_producer_init
576 ):
577 def _test_configure_scaling_groups_get_vnfr(*args, **kwargs):
578 if "1" in args[1]:
579 return vnfr_record_mocks[0]
580 if "2" in args[1]:
581 return vnfr_record_mocks[1]
583 async def _test_configure_vnf_alarms_create_alarm(*args, **kwargs):
584 return uuid.uuid4()
586 kafka_producer_init.return_value = None
587 get_vnfr.side_effect = _test_configure_scaling_groups_get_vnfr
588 get_nsr.return_value = nsr_record_mock
589 get_vnfd.return_value = vnfd_record_mock
590 create_alarm.side_effect = _test_configure_vnf_alarms_create_alarm
591 config = Config()
592 agent = PolicyModuleAgent(config)
593 self.loop.run_until_complete(
594 agent.alarming_service.configure_vnf_alarms("test_nsr_id")
595 )
596 create_alarm.assert_any_call(
597 metric_name="average_memory_utilization",
598 ns_id="test_nsr_id",
599 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
600 vnf_member_index="1",
601 threshold=20.0,
602 operation="LT",
603 action="{'webhook': ['localhost:9090', 'localhost:9090', 'localhost:9090']}",
604 vnfr=vnfr_record_mocks[0],
605 vnfd=vnfd_record_mock,
606 )
607 create_alarm.assert_any_call(
608 metric_name="average_memory_utilization",
609 ns_id="test_nsr_id",
610 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
611 vnf_member_index="2",
612 threshold=20.0,
613 operation="LT",
614 action="{'webhook': ['localhost:9090', 'localhost:9090', 'localhost:9090']}",
615 vnfr=vnfr_record_mocks[1],
616 vnfd=vnfd_record_mock,
617 )
619 @patch.object(DbMongo, "db_connect", Mock())
620 @patch.object(AIOKafkaProducer, "__init__")
621 @patch.object(MonClient, "create_alarm")
622 @patch.object(CommonDbClient, "get_vnfd")
623 @patch.object(CommonDbClient, "get_nsr")
624 @patch.object(CommonDbClient, "get_vnfr")
625 def test_configure_healing_alarms(
626 self, get_vnfr, get_nsr, get_vnfd, create_alarm, kafka_producer_init
627 ):
628 def _test_configure_scaling_groups_get_vnfr(*args, **kwargs):
629 if "1" in args[1]:
630 return vnfr_record_mocks[0]
631 if "2" in args[1]:
632 return vnfr_record_mocks[1]
634 async def _test_configure_healing_alarms_create_alarm(*args, **kwargs):
635 return uuid.uuid4()
637 kafka_producer_init.return_value = None
638 get_vnfr.side_effect = _test_configure_scaling_groups_get_vnfr
639 get_nsr.return_value = nsr_record_mock
640 get_vnfd.return_value = vnfd_record_mock
641 create_alarm.side_effect = _test_configure_healing_alarms_create_alarm
642 config = Config()
643 agent = PolicyModuleAgent(config)
644 self.loop.run_until_complete(
645 agent.healing_service.configure_healing_alarms("test_nsr_id")
646 )
647 create_alarm.assert_any_call(
648 metric_name="vm_status",
649 ns_id="test_nsr_id",
650 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
651 vnf_member_index="1",
652 threshold=1,
653 operation="LT",
654 statistic="AVERAGE",
655 )
656 create_alarm.assert_any_call(
657 metric_name="vm_status",
658 ns_id="test_nsr_id",
659 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
660 vnf_member_index="2",
661 threshold=1,
662 operation="LT",
663 statistic="AVERAGE",
664 )
667if __name__ == "__main__":
668 unittest.main()