Enable black and pylint in tox.ini
[osm/POL.git] / osm_policy_module / tests / integration / test_policy_agent.py
1 # -*- coding: utf-8 -*-
2
3 # Copyright 2018 Whitestack, LLC
4 # *************************************************************
5
6 # This file is part of OSM Monitoring module
7 # All Rights Reserved to Whitestack, LLC
8
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
12
13 # http://www.apache.org/licenses/LICENSE-2.0
14
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.
20
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact: bdiaz@whitestack.com or glavado@whitestack.com
23 ##
24 import asyncio
25 import logging
26 import os
27 import sys
28 import unittest
29 import uuid
30 from unittest.mock import patch, Mock
31
32 from kafka import KafkaProducer
33 from osm_common.dbmongo import DbMongo
34 from playhouse.db_url import connect
35
36 from osm_policy_module.common.common_db_client import CommonDbClient
37 from osm_policy_module.common.mon_client import MonClient
38 from osm_policy_module.core import database
39 from osm_policy_module.core.agent import PolicyModuleAgent
40 from osm_policy_module.core.config import Config
41 from osm_policy_module.core.database import (
42 ScalingGroup,
43 ScalingAlarm,
44 ScalingPolicy,
45 ScalingCriteria,
46 VnfAlarm,
47 AlarmAction,
48 HealingAction,
49 )
50
51 log = logging.getLogger()
52 log.level = logging.INFO
53 stream_handler = logging.StreamHandler(sys.stdout)
54 log.addHandler(stream_handler)
55
56 nsr_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 }
171
172 vnfr_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 ]
246
247 nsd_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 }
293
294
295 vnfd_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 }
457
458 MODELS = [
459 ScalingGroup,
460 ScalingPolicy,
461 ScalingCriteria,
462 ScalingAlarm,
463 VnfAlarm,
464 AlarmAction,
465 HealingAction,
466 ]
467
468
469 class 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()
479
480 def tearDown(self):
481 super()
482 os.remove("test_db.sqlite")
483
484 @patch.object(DbMongo, "db_connect", Mock())
485 @patch.object(KafkaProducer, "__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]
498
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.")
505
506 async def _test_configure_scaling_groups_create_alarm(*args, **kwargs):
507 return uuid.uuid4()
508
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, self.loop)
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 )
529 create_alarm.assert_not_called_with(
530 metric_name="average_memory_utilization",
531 ns_id="test_nsr_id",
532 operation="LT",
533 threshold=20,
534 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
535 vnf_member_index="1",
536 action="scale_out",
537 )
538 create_alarm.assert_any_call(
539 metric_name="average_memory_utilization",
540 ns_id="test_nsr_id",
541 operation="GT",
542 threshold=80,
543 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
544 vnf_member_index="2",
545 action="scale_out",
546 )
547 create_alarm.assert_not_called_with(
548 metric_name="average_memory_utilization",
549 ns_id="test_nsr_id",
550 operation="LT",
551 threshold=20,
552 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
553 vnf_member_index="2",
554 action="scale_out",
555 )
556 scaling_record = ScalingGroup.get()
557 self.assertEqual(scaling_record.name, "scale_cirros_vnfd-VM")
558 self.assertEqual(scaling_record.nsr_id, "test_nsr_id")
559
560 @patch.object(DbMongo, "db_connect", Mock())
561 @patch.object(KafkaProducer, "__init__")
562 @patch.object(MonClient, "create_alarm")
563 @patch.object(CommonDbClient, "get_vnfd")
564 @patch.object(CommonDbClient, "get_nsr")
565 @patch.object(CommonDbClient, "get_vnfr")
566 def test_configure_vnf_alarms(
567 self, get_vnfr, get_nsr, get_vnfd, create_alarm, kafka_producer_init
568 ):
569 def _test_configure_scaling_groups_get_vnfr(*args, **kwargs):
570 if "1" in args[1]:
571 return vnfr_record_mocks[0]
572 if "2" in args[1]:
573 return vnfr_record_mocks[1]
574
575 async def _test_configure_vnf_alarms_create_alarm(*args, **kwargs):
576 return uuid.uuid4()
577
578 kafka_producer_init.return_value = None
579 get_vnfr.side_effect = _test_configure_scaling_groups_get_vnfr
580 get_nsr.return_value = nsr_record_mock
581 get_vnfd.return_value = vnfd_record_mock
582 create_alarm.side_effect = _test_configure_vnf_alarms_create_alarm
583 config = Config()
584 agent = PolicyModuleAgent(config, self.loop)
585 self.loop.run_until_complete(
586 agent.alarming_service.configure_vnf_alarms("test_nsr_id")
587 )
588 create_alarm.assert_any_call(
589 metric_name="average_memory_utilization",
590 ns_id="test_nsr_id",
591 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
592 vnf_member_index="1",
593 threshold=20.0,
594 operation="LT",
595 action="{'webhook': ['localhost:9090', 'localhost:9090', 'localhost:9090']}",
596 )
597 create_alarm.assert_any_call(
598 metric_name="average_memory_utilization",
599 ns_id="test_nsr_id",
600 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
601 vnf_member_index="2",
602 threshold=20.0,
603 operation="LT",
604 action="{'webhook': ['localhost:9090', 'localhost:9090', 'localhost:9090']}",
605 )
606
607 @patch.object(DbMongo, "db_connect", Mock())
608 @patch.object(KafkaProducer, "__init__")
609 @patch.object(MonClient, "create_alarm")
610 @patch.object(CommonDbClient, "get_vnfd")
611 @patch.object(CommonDbClient, "get_nsr")
612 @patch.object(CommonDbClient, "get_vnfr")
613 def test_configure_healing_alarms(
614 self, get_vnfr, get_nsr, get_vnfd, create_alarm, kafka_producer_init
615 ):
616 def _test_configure_scaling_groups_get_vnfr(*args, **kwargs):
617 if "1" in args[1]:
618 return vnfr_record_mocks[0]
619 if "2" in args[1]:
620 return vnfr_record_mocks[1]
621
622 async def _test_configure_healing_alarms_create_alarm(*args, **kwargs):
623 return uuid.uuid4()
624
625 kafka_producer_init.return_value = None
626 get_vnfr.side_effect = _test_configure_scaling_groups_get_vnfr
627 get_nsr.return_value = nsr_record_mock
628 get_vnfd.return_value = vnfd_record_mock
629 create_alarm.side_effect = _test_configure_healing_alarms_create_alarm
630 config = Config()
631 agent = PolicyModuleAgent(config, self.loop)
632 self.loop.run_until_complete(
633 agent.healing_service.configure_healing_alarms("test_nsr_id")
634 )
635 create_alarm.assert_any_call(
636 metric_name="vm_status",
637 ns_id="test_nsr_id",
638 vdu_name="cirros_ns-1-cirros_vnfd-VM-1",
639 vnf_member_index="1",
640 threshold=1,
641 operation="LT",
642 statistic="AVERAGE",
643 )
644 create_alarm.assert_any_call(
645 metric_name="vm_status",
646 ns_id="test_nsr_id",
647 vdu_name="cirros_ns-2-cirros_vnfd-VM-1",
648 vnf_member_index="2",
649 threshold=1,
650 operation="LT",
651 statistic="AVERAGE",
652 )
653
654
655 if __name__ == "__main__":
656 unittest.main()