From c30b438f725bbbd56afee3a21a368d75fe0477cd Mon Sep 17 00:00:00 2001 From: Yuvaraja Mariappan Date: Mon, 24 Jul 2017 16:50:57 -0700 Subject: [PATCH] link-local service-health-check support for non service vmis 1. For non service vms the vmi has to be set with the annotation '_service_vm_ = False'. Service Monitor uses this annoation to diffrentiate between non service vms and service vms while updating the service health check link 2. Added check in api-sever to disqualify if the vmi of the non service vm refers to 'link-local' type service-health-check 3. Added unit-test for point 1 and 2 Change-Id: I3b023d7544edf55438b29484df50a90d199dec88 Partial-bug: #1702783 --- .../api-server/tests/test_crud_basic.py | 20 ++++++++ src/config/api-server/vnc_cfg_types.py | 42 ++++++++++++++++ .../svc-monitor/svc_monitor/config_db.py | 8 +++ .../svc-monitor/svc_monitor/port_tuple.py | 2 +- .../svc_monitor/tests/test_svc_monitor.py | 50 ++++++++++++++++++- 5 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/config/api-server/tests/test_crud_basic.py b/src/config/api-server/tests/test_crud_basic.py index bedbaa2314c..829a7048a5d 100644 --- a/src/config/api-server/tests/test_crud_basic.py +++ b/src/config/api-server/tests/test_crud_basic.py @@ -555,6 +555,26 @@ def test_bridge_domain_delete_vn_ref_with_bd_link(self): self._vnc_lib.virtual_machine_interface_update(vmi) # end test_bridge_domain_with_multiple_bd_in_vn + def test_vmi_with_end_to_end_shc(self): + project = Project() + vn = VirtualNetwork('vn-%s' %(self.id())) + self._vnc_lib.virtual_network_create(vn) + vmi_obj = VirtualMachineInterface( + str(uuid.uuid4()), parent_obj=project) + vmi_obj.uuid = vmi_obj.name + vmi_obj.set_virtual_network(vn) + vmi_id = self._vnc_lib.virtual_machine_interface_create(vmi_obj) + + shc_props = ServiceHealthCheckType() + shc_props.enabled = True + shc_props.health_check_type = 'end-to-end' + shc_obj = ServiceHealthCheck(str(uuid.uuid4()), parent_obj=project, + service_health_check_properties=shc_props) + shc_id = self._vnc_lib.service_health_check_create(shc_obj) + with ExpectedException(BadRequest) as e: + self._vnc_lib.ref_update('virtual-machine-interface', vmi_id, + 'service-health-check', shc_id, None, 'ADD') + def test_sub_interfaces_with_same_vlan_tags(self): vn = VirtualNetwork('vn-%s' %(self.id())) self._vnc_lib.virtual_network_create(vn) diff --git a/src/config/api-server/vnc_cfg_types.py b/src/config/api-server/vnc_cfg_types.py index c8f06366f09..01029fdcd7a 100644 --- a/src/config/api-server/vnc_cfg_types.py +++ b/src/config/api-server/vnc_cfg_types.py @@ -972,6 +972,39 @@ def _check_port_security_and_address_pairs(cls, obj_dict, db_dict={}): return True, "" + @classmethod + def _check_service_health_check_type(cls, obj_dict, db_dict, db_conn): + service_health_check_refs = \ + obj_dict.get('service_health_check_refs', None) + if not service_health_check_refs: + return (True, '') + + if obj_dict and obj_dict.get('port_tuple_refs', None): + return (True, '') + + if db_dict and db_dict.get('port_tuple_refs', None): + return (True, '') + + for shc in service_health_check_refs or []: + if 'uuid' in shc: + shc_uuid = shc['uuid'] + else: + shc_fq_name = shc['to'] + shc_uuid = db_conn.fq_name_to_uuid('service_health_check', shc_fq_name) + ok, result = cls.dbe_read(db_conn, 'service_health_check', shc_uuid, + obj_fields=['service_health_check_properties']) + if not ok: + return (ok, result) + + shc_type = result['service_health_check_properties']['health_check_type'] + if shc_type != 'link-local': + msg = "Virtual machine interface(%s) of non service vm can only refer "\ + "link-local type service health check"\ + % obj_dict['uuid'] + return (False, (400, msg)) + + return (True, '') + @classmethod def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): vn_dict = obj_dict['virtual_network_refs'][0] @@ -1084,6 +1117,10 @@ def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): (ok, result) = cls._check_port_security_and_address_pairs(obj_dict) + if not ok: + return ok, result + + (ok, result) = cls._check_service_health_check_type(obj_dict, None, db_conn) if not ok: return ok, result @@ -1190,6 +1227,11 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, if not ok: return ok, result + (ok, result) = cls._check_service_health_check_type( + obj_dict, read_result, db_conn) + if not ok: + return ok, result + return True, "" # end pre_dbe_update diff --git a/src/config/svc-monitor/svc_monitor/config_db.py b/src/config/svc-monitor/svc_monitor/config_db.py index 7357c260a9f..2bb2231f01d 100644 --- a/src/config/svc-monitor/svc_monitor/config_db.py +++ b/src/config/svc-monitor/svc_monitor/config_db.py @@ -513,6 +513,8 @@ def __init__(self, uuid, obj_dict=None): self.port_tuple = None self.fat_flow_ports = set() self.aaps = None + self.annotations = None + self.service_vm = True obj_dict = self.update(obj_dict) self.add_to_parent(obj_dict) # end __init__ @@ -548,6 +550,12 @@ def update(self, obj=None): self.update_single_ref('physical_interface',obj) self.update_multiple_refs('security_group', obj) self.update_single_ref('port_tuple', obj) + self.annotations = obj.get('annotations', None) + if self.annotations: + for kvp in self.annotations['key_value_pair'] or []: + if kvp['key'] == '_service_vm_': + self.service_vm = eval(kvp['value']) + break if self.virtual_machine: vm = VirtualMachineSM.get(self.virtual_machine) if vm: diff --git a/src/config/svc-monitor/svc_monitor/port_tuple.py b/src/config/svc-monitor/svc_monitor/port_tuple.py index 8b51890744e..fa80f0c1e96 100644 --- a/src/config/svc-monitor/svc_monitor/port_tuple.py +++ b/src/config/svc-monitor/svc_monitor/port_tuple.py @@ -276,7 +276,7 @@ def delete_old_vmi_links(self, vmi): for health_id in list(vmi.service_health_checks): health = ServiceHealthCheckSM.get(health_id) - if health and health.service_instances: + if health and health.service_instances and vmi.service_vm == True: self._vnc_lib.ref_update('virtual-machine-interface', vmi.uuid, 'service-health-check', health.uuid, None, 'DELETE') vmi.service_health_checks.remove(health_id) diff --git a/src/config/svc-monitor/svc_monitor/tests/test_svc_monitor.py b/src/config/svc-monitor/svc_monitor/tests/test_svc_monitor.py index 6670dc6c4db..a056a91e248 100644 --- a/src/config/svc-monitor/svc_monitor/tests/test_svc_monitor.py +++ b/src/config/svc-monitor/svc_monitor/tests/test_svc_monitor.py @@ -50,6 +50,11 @@ u'fq_name': [u'fake-domain', u'fake-project', u'fake-domain__fake-project__fake-instance__1__left__0'], } +vmi_update_info = { + u'oper': u'UPDATE', u'uuid': u'fake-vmi', u'type': u'virtual-machine-interface', + u'fq_name': [u'fake-domain', u'fake-project', u'fake-domain__fake-project__'], +} + vmi_del_info = { u'oper': u'DELETE', u'uuid': u'left-vmi', u'type': u'virtual-machine-interface', u'fq_name': [u'fake-domain', u'fake-project', u'left-vmi'], @@ -392,6 +397,22 @@ def add_irt(self, name, uuid): config_db.InterfaceRouteTableSM.locate(uuid) return irt_obj + def add_shc(self, name, uuid, parent_obj, shc_props, si_obj=None): + shc = ServiceHealthCheck(name=name, parent_obj=parent_obj, + service_health_check_properties=shc_props) + if si_obj: + si_inf_tag = ServiceInterfaceTag(interface_type='left') + shc.add_service_instance(si_obj, si_inf_tag) + shc._pending_field_updates.add('service_instance_refs') + shc_dict = self.obj_to_dict(shc) + shc_dict['uuid'] = uuid + shc_dict['parent_uuid'] = parent_obj.uuid + shc_obj = ServiceHealthCheck.from_dict(**shc_dict) + config_db.ServiceHealthCheckSM._object_db.object_read = \ + mock.Mock(return_value=(True, [shc_dict])) + config_db.ServiceHealthCheckSM.locate(uuid) + return shc_obj + def add_si(self, name, uuid, st): si = ServiceInstance(name=name) si.set_service_template(st) @@ -438,8 +459,10 @@ def add_vn(self, name, uuid, parent_obj): config_db.VirtualNetworkSM.locate(uuid) return net_obj - def add_vmi(self, name, uuid, parent_obj, net_obj, vm_obj=None, irt_obj=None): - vmi = VirtualMachineInterface(name=name, parent_obj=parent_obj) + def add_vmi(self, name, uuid, parent_obj, net_obj, + vm_obj=None, irt_obj=None, shc_obj=None, annotations=None): + vmi = VirtualMachineInterface(name=name, + parent_obj=parent_obj, annotations=annotations) vmi.set_virtual_network(net_obj) if vm_obj: vmi.set_virtual_machine(vm_obj) @@ -447,6 +470,9 @@ def add_vmi(self, name, uuid, parent_obj, net_obj, vm_obj=None, irt_obj=None): if irt_obj: vmi.add_interface_route_table(irt_obj) vmi._pending_field_updates.add('interface_route_table_refs') + if shc_obj: + vmi.add_service_health_check(shc_obj) + vmi._pending_field_updates.add('service_health_check_refs') vmi_dict = self.obj_to_dict(vmi) vmi_dict['parent_uuid'] = parent_obj.uuid vmi_dict['uuid'] = uuid @@ -870,6 +896,26 @@ def test_svc_monitor_vm_delayed_vn_add(self): match_str = "SI %s creation success" % (':').join(si.fq_name) ServiceMonitorLogger.info.assert_any_call(match_str) + def test_svc_monitor_non_service_vmi_service_health_check(self): + vm_obj = self.add_vm("fake-vm", 'fake-vm', None, 'virtual-machine') + project = self.add_project('fake-project', 'fake-project') + net_obj = self.add_vn('fake-vn', 'fake-vn', project) + shc_props = ServiceHealthCheckType() + shc_props.enabled = True + shc_props.health_check_type = 'link-local' + st_obj = self.add_st('fake-template', 'fake-template') + si_obj = self.add_si('fake-instance', 'fake-instance', st_obj) + shc_obj = self.add_shc('fake-shc', 'fake-shc', project, + shc_props, si_obj=si_obj) + kvps_list = [{'key': '_service_vm_', 'value': 'False'}] + annotations = {} + annotations['key_value_pair'] = kvps_list + vmi_obj = self.add_vmi('fake-domain__fake-project__', 'fake-vmi', project, + net_obj, vm_obj, shc_obj=shc_obj, annotations=annotations) + self._svc_monitor.rabbit._vnc_subscribe_callback(vmi_update_info) + vmi = config_db.VirtualMachineInterfaceSM.get('fake-vmi') + self.assertEqual(len(vmi.service_health_checks), 1) + def test_svc_monitor_vmi_add(self): st_obj = self.add_st('fake-template', 'fake-template') si = test_utils.create_test_si(name='fake-instance', count=1,