diff --git a/src/config/api-server/vnc_cfg_ifmap.py b/src/config/api-server/vnc_cfg_ifmap.py index 579ef75ab06..e6fee4a19ec 100644 --- a/src/config/api-server/vnc_cfg_ifmap.py +++ b/src/config/api-server/vnc_cfg_ifmap.py @@ -384,6 +384,8 @@ def _delete_id_pair_meta(self, id1, id2, metadata): # del meta,id2 from cache and del id if this was last meta def _id_to_metas_delete(id1, id2, meta_name): + if id1 not in self._id_to_metas: + return if meta_name not in self._id_to_metas[id1]: return if not self._id_to_metas[id1][meta_name]: diff --git a/src/config/svc-monitor/SConscript b/src/config/svc-monitor/SConscript index ef831d7ca44..3ccb8170d66 100644 --- a/src/config/svc-monitor/SConscript +++ b/src/config/svc-monitor/SConscript @@ -16,6 +16,7 @@ sources = [ 'svc_monitor/__init__.py', 'svc_monitor/svc_monitor.py', 'svc_monitor/instance_manager.py', + 'svc_monitor/virtual_machine_manager.py', 'svc_monitor/vrouter_instance_manager.py', 'svc_monitor/db.py', 'svc_monitor/logger.py', diff --git a/src/config/svc-monitor/svc_monitor/instance_manager.py b/src/config/svc-monitor/svc_monitor/instance_manager.py index 661d9d7e819..611347e38e9 100644 --- a/src/config/svc-monitor/svc_monitor/instance_manager.py +++ b/src/config/svc-monitor/svc_monitor/instance_manager.py @@ -24,9 +24,6 @@ from cfgm_common import svc_info from vnc_api.vnc_api import * -from novaclient import client as nc -from novaclient import exceptions as nc_exc - @six.add_metaclass(abc.ABCMeta) class InstanceManager(object): @@ -362,246 +359,6 @@ def _get_nic_info(self, si_obj, si_props, st_props): return nics -class VirtualMachineManager(InstanceManager): - - def _create_svc_vm(self, instance_name, image_name, nics, - flavor_name, st_obj, si_obj, avail_zone): - - proj_name = si_obj.get_parent_fq_name()[-1] - if flavor_name: - flavor = self.novaclient_oper('flavors', 'find', proj_name, - name=flavor_name) - else: - flavor = self.novaclient_oper('flavors', 'find', proj_name, - ram=4096) - - image = '' - try: - image = self.novaclient_oper('images', 'find', proj_name, - name=image_name) - except nc_exc.NotFound: - self.logger.log( - "Error: Image %s not found in project %s" - % (image_name, proj_name)) - return - except nc_exc.NoUniqueMatch: - self.logger.log( - "Error: Multiple images %s found in project %s" - % (image_name, proj_name)) - return - - # create port - nics_with_port = [] - for nic in nics: - nic_with_port = {} - vmi_obj = self._create_svc_vm_port(nic, instance_name, - st_obj, si_obj) - nic_with_port['port-id'] = vmi_obj.get_uuid() - nics_with_port.append(nic_with_port) - - # launch vm - self.logger.log('Launching VM : ' + instance_name) - nova_vm = self.novaclient_oper('servers', 'create', proj_name, - name=instance_name, image=image, - flavor=flavor, nics=nics_with_port, - availability_zone=avail_zone) - nova_vm.get() - self.logger.log('Created VM : ' + str(nova_vm)) - - # create vnc VM object and link to SI - try: - proj_obj = self._vnc_lib.project_read( - fq_name=si_obj.get_parent_fq_name()) - vm_obj = VirtualMachine(nova_vm.id) - vm_obj.uuid = nova_vm.id - self._vnc_lib.virtual_machine_create(vm_obj) - except RefsExistError: - vm_obj = self._vnc_lib.virtual_machine_read(id=nova_vm.id) - - vm_obj.add_service_instance(si_obj) - self._vnc_lib.virtual_machine_update(vm_obj) - self.logger.log("Info: VM %s updated SI %s" % - (vm_obj.get_fq_name_str(), si_obj.get_fq_name_str())) - - return nova_vm - - def create_service(self, st_obj, si_obj): - si_props = si_obj.get_service_instance_properties() - st_props = st_obj.get_service_template_properties() - if st_props is None: - self.logger.log("Cannot find service template associated to " - "service instance %s" % si_obj.get_fq_name_str()) - return - - flavor = st_props.get_flavor() - image_name = st_props.get_image_name() - if image_name is None: - self.logger.log("Error: Image name not present in %s" % - (st_obj.name)) - return - - # populate nic information - nics = self._get_nic_info(si_obj, si_props, st_props) - - # get availability zone - avail_zone = None - if st_props.get_availability_zone_enable(): - avail_zone = si_props.get_availability_zone() - elif self._args.availability_zone: - avail_zone = self._args.availability_zone - - # create and launch vm - vm_back_refs = si_obj.get_virtual_machine_back_refs() - proj_name = si_obj.get_parent_fq_name()[-1] - max_instances = si_props.get_scale_out().get_max_instances() - self.db.service_instance_insert(si_obj.get_fq_name_str(), - {'max-instances': str(max_instances)}) - instances = [] - for inst_count in range(0, max_instances): - instance_name = self._get_instance_name(si_obj, inst_count) - exists = False - for vm_back_ref in vm_back_refs or []: - vm = self.novaclient_oper('servers', 'find', proj_name, - id=vm_back_ref['uuid']) - if vm.name == instance_name: - exists = True - break - - if exists: - vm_uuid = vm_back_ref['uuid'] - state = 'active' - else: - vm = self._create_svc_vm(instance_name, image_name, nics, - flavor, st_obj, si_obj, avail_zone) - if vm is None: - continue - vm_uuid = vm.id - state = 'pending' - - # store vm, instance in db; use for linking when VM is up - vm_db_entry = self._set_vm_db_info(inst_count, instance_name, - vm_uuid, state) - self.db.service_instance_insert(si_obj.get_fq_name_str(), - vm_db_entry) - instances.append({'uuid': vm_uuid}) - - # uve trace - self.logger.uve_svc_instance(si_obj.get_fq_name_str(), - status='CREATE', vms=instances, - st_name=st_obj.get_fq_name_str()) - - def delete_service(self, vm_uuid, proj_name=None): - try: - self._vnc_lib.virtual_machine_delete(id=vm_uuid) - except (NoIdError, RefsExistError): - pass - - try: - self.novaclient_oper('servers', 'find', proj_name, - id=vm_uuid).delete() - except nc_exc.NotFound: - raise KeyError - - def check_service(self, si_obj, proj_name=None): - status = 'ACTIVE' - vm_list = {} - vm_back_refs = si_obj.get_virtual_machine_back_refs() - for vm_back_ref in vm_back_refs or []: - try: - vm = self.novaclient_oper('servers', 'find', proj_name, - id=vm_back_ref['uuid']) - vm_list[vm.name] = vm - except nc_exc.NotFound: - self._vnc_lib.virtual_machine_delete(id=vm_back_ref['uuid']) - except (NoIdError, RefsExistError): - pass - - # check status of VMs - si_props = si_obj.get_service_instance_properties() - max_instances = si_props.get_scale_out().get_max_instances() - for inst_count in range(0, max_instances): - instance_name = self._get_instance_name(si_obj, inst_count) - if instance_name not in vm_list.keys(): - status = 'ERROR' - elif vm_list[instance_name].status == 'ERROR': - try: - self.delete_service(vm_list[instance_name].id, proj_name) - except KeyError: - pass - status = 'ERROR' - - # check change in instance count - if vm_back_refs and (max_instances > len(vm_back_refs)): - status = 'ERROR' - elif vm_back_refs and (max_instances < len(vm_back_refs)): - for vm_back_ref in vm_back_refs: - try: - self.delete_service(vm_back_ref['uuid'], proj_name) - except KeyError: - pass - status = 'ERROR' - - return status - - def _novaclient_get(self, proj_name, reauthenticate=False): - # return cache copy when reauthenticate is not requested - if not reauthenticate: - client = self._nova.get(proj_name) - if client is not None: - return client - - auth_url = self._args.auth_protocol + '://' + self._args.auth_host \ - + ':' + self._args.auth_port + '/' + self._args.auth_version - self._nova[proj_name] = nc.Client( - '2', username=self._args.admin_user, project_id=proj_name, - api_key=self._args.admin_password, - region_name=self._args.region_name, service_type='compute', - auth_url=auth_url, insecure=self._args.auth_insecure) - return self._nova[proj_name] - - def novaclient_oper(self, resource, oper, proj_name, **kwargs): - n_client = self._novaclient_get(proj_name) - try: - resource_obj = getattr(n_client, resource) - oper_func = getattr(resource_obj, oper) - return oper_func(**kwargs) - except nc_exc.Unauthorized: - n_client = self._novaclient_get(proj_name, True) - oper_func = getattr(n_client, oper) - return oper_func(**kwargs) - - def update_static_routes(self, si_obj): - # get service instance interface list - si_props = si_obj.get_service_instance_properties() - si_if_list = si_props.get_interface_list() - if not si_if_list: - return - - st_list = si_obj.get_service_template_refs() - fq_name = st_list[0]['to'] - st_obj = self._vnc_lib.service_template_read(fq_name=fq_name) - st_props = st_obj.get_service_template_properties() - st_if_list = st_props.get_interface_type() - - for idx in range(0, len(si_if_list)): - si_if = si_if_list[idx] - static_routes = si_if.get_static_routes() - if not static_routes: - static_routes = {'route':[]} - - # update static routes - try: - rt_fq_name = self._get_if_route_table_name( - st_if_list[idx].get_service_interface_type(), - si_obj) - rt_obj = self._vnc_lib.interface_route_table_read( - fq_name=rt_fq_name) - rt_obj.set_interface_route_table_routes(static_routes) - self._vnc_lib.interface_route_table_update(rt_obj) - except NoIdError: - pass - - class VRouterHostedManager(InstanceManager): @abc.abstractmethod def create_service(self, st_obj, si_obj): diff --git a/src/config/svc-monitor/svc_monitor/svc_monitor.py b/src/config/svc-monitor/svc_monitor/svc_monitor.py index 2da736f71b1..9fa243bac98 100644 --- a/src/config/svc-monitor/svc_monitor/svc_monitor.py +++ b/src/config/svc-monitor/svc_monitor/svc_monitor.py @@ -125,7 +125,7 @@ def post_init(self, vnc_lib, args=None): # load virtual machine instance manager self.vm_manager = importutils.import_object( - 'svc_monitor.instance_manager.VirtualMachineManager', + 'svc_monitor.virtual_machine_manager.VirtualMachineManager', self._vnc_lib, self.db, self.logger, self.vrouter_scheduler, self._args) diff --git a/src/config/svc-monitor/svc_monitor/virtual_machine_manager.py b/src/config/svc-monitor/svc_monitor/virtual_machine_manager.py new file mode 100644 index 00000000000..c1163332505 --- /dev/null +++ b/src/config/svc-monitor/svc_monitor/virtual_machine_manager.py @@ -0,0 +1,266 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2014 Cloudwatt +# All Rights Reserved. +# +# 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. +# +# @author: Rudra Rugge + +from cfgm_common import svc_info +from vnc_api.vnc_api import * +from instance_manager import InstanceManager + +from novaclient import client as nc +from novaclient import exceptions as nc_exc + +class VirtualMachineManager(InstanceManager): + + def _create_svc_vm(self, instance_name, image_name, nics, + flavor_name, st_obj, si_obj, avail_zone): + + proj_name = si_obj.get_parent_fq_name()[-1] + if flavor_name: + flavor = self.novaclient_oper('flavors', 'find', proj_name, + name=flavor_name) + else: + flavor = self.novaclient_oper('flavors', 'find', proj_name, + ram=4096) + if not flavor: + return + + image = self.novaclient_oper('images', 'find', proj_name, + name=image_name) + if not image: + return + + # create port + nics_with_port = [] + for nic in nics: + nic_with_port = {} + vmi_obj = self._create_svc_vm_port(nic, instance_name, + st_obj, si_obj) + nic_with_port['port-id'] = vmi_obj.get_uuid() + nics_with_port.append(nic_with_port) + + # launch vm + self.logger.log('Launching VM : ' + instance_name) + nova_vm = self.novaclient_oper('servers', 'create', proj_name, + name=instance_name, image=image, + flavor=flavor, nics=nics_with_port, + availability_zone=avail_zone) + nova_vm.get() + self.logger.log('Created VM : ' + str(nova_vm)) + + # create vnc VM object and link to SI + try: + proj_obj = self._vnc_lib.project_read( + fq_name=si_obj.get_parent_fq_name()) + vm_obj = VirtualMachine(nova_vm.id) + vm_obj.uuid = nova_vm.id + self._vnc_lib.virtual_machine_create(vm_obj) + except RefsExistError: + vm_obj = self._vnc_lib.virtual_machine_read(id=nova_vm.id) + + vm_obj.add_service_instance(si_obj) + self._vnc_lib.virtual_machine_update(vm_obj) + self.logger.log("Info: VM %s updated SI %s" % + (vm_obj.get_fq_name_str(), si_obj.get_fq_name_str())) + + return nova_vm + + def create_service(self, st_obj, si_obj): + si_props = si_obj.get_service_instance_properties() + st_props = st_obj.get_service_template_properties() + if st_props is None: + self.logger.log("Cannot find service template associated to " + "service instance %s" % si_obj.get_fq_name_str()) + return + + flavor = st_props.get_flavor() + image_name = st_props.get_image_name() + if image_name is None: + self.logger.log("Error: Image name not present in %s" % + (st_obj.name)) + return + + # populate nic information + nics = self._get_nic_info(si_obj, si_props, st_props) + + # get availability zone + avail_zone = None + if st_props.get_availability_zone_enable(): + avail_zone = si_props.get_availability_zone() + elif self._args.availability_zone: + avail_zone = self._args.availability_zone + + # create and launch vm + vm_back_refs = si_obj.get_virtual_machine_back_refs() + proj_name = si_obj.get_parent_fq_name()[-1] + max_instances = si_props.get_scale_out().get_max_instances() + self.db.service_instance_insert(si_obj.get_fq_name_str(), + {'max-instances': str(max_instances)}) + instances = [] + for inst_count in range(0, max_instances): + instance_name = self._get_instance_name(si_obj, inst_count) + vm_exists = False + for vm_back_ref in vm_back_refs or []: + vm = self.novaclient_oper('servers', 'find', proj_name, + id=vm_back_ref['uuid']) + if vm and vm.name == instance_name: + vm_exists = True + break + + if vm_exists: + vm_uuid = vm_back_ref['uuid'] + state = 'active' + else: + vm = self._create_svc_vm(instance_name, image_name, nics, + flavor, st_obj, si_obj, avail_zone) + if vm is None: + continue + vm_uuid = vm.id + state = 'pending' + + # store vm, instance in db; use for linking when VM is up + vm_db_entry = self._set_vm_db_info(inst_count, instance_name, + vm_uuid, state) + self.db.service_instance_insert(si_obj.get_fq_name_str(), + vm_db_entry) + instances.append({'uuid': vm_uuid}) + + # uve trace + self.logger.uve_svc_instance(si_obj.get_fq_name_str(), + status='CREATE', vms=instances, + st_name=st_obj.get_fq_name_str()) + + def delete_service(self, vm_uuid, proj_name=None): + try: + self._vnc_lib.virtual_machine_delete(id=vm_uuid) + except (NoIdError, RefsExistError): + pass + + vm = self.novaclient_oper('servers', 'find', proj_name, id = vm_uuid) + if vm: + vm.delete() + else: + raise KeyError + + def check_service(self, si_obj, proj_name=None): + status = 'ACTIVE' + vm_list = {} + vm_back_refs = si_obj.get_virtual_machine_back_refs() + for vm_back_ref in vm_back_refs or []: + try: + vm = self.novaclient_oper('servers', 'find', proj_name, + id=vm_back_ref['uuid']) + vm_list[vm.name] = vm + except nc_exc.NotFound: + self._vnc_lib.virtual_machine_delete(id=vm_back_ref['uuid']) + except (NoIdError, RefsExistError): + pass + + # check status of VMs + si_props = si_obj.get_service_instance_properties() + max_instances = si_props.get_scale_out().get_max_instances() + for inst_count in range(0, max_instances): + instance_name = self._get_instance_name(si_obj, inst_count) + if instance_name not in vm_list.keys(): + status = 'ERROR' + elif vm_list[instance_name].status == 'ERROR': + try: + self.delete_service(vm_list[instance_name].id, proj_name) + except KeyError: + pass + status = 'ERROR' + + # check change in instance count + if vm_back_refs and (max_instances > len(vm_back_refs)): + status = 'ERROR' + elif vm_back_refs and (max_instances < len(vm_back_refs)): + for vm_back_ref in vm_back_refs: + try: + self.delete_service(vm_back_ref['uuid'], proj_name) + except KeyError: + pass + status = 'ERROR' + + return status + + def _novaclient_get(self, proj_name, reauthenticate=False): + # return cache copy when reauthenticate is not requested + if not reauthenticate: + client = self._nova.get(proj_name) + if client is not None: + return client + + auth_url = self._args.auth_protocol + '://' + self._args.auth_host \ + + ':' + self._args.auth_port + '/' + self._args.auth_version + self._nova[proj_name] = nc.Client( + '2', username=self._args.admin_user, project_id=proj_name, + api_key=self._args.admin_password, + region_name=self._args.region_name, service_type='compute', + auth_url=auth_url, insecure=self._args.auth_insecure) + return self._nova[proj_name] + + def novaclient_oper(self, resource, oper, proj_name, **kwargs): + n_client = self._novaclient_get(proj_name) + try: + resource_obj = getattr(n_client, resource) + oper_func = getattr(resource_obj, oper) + return oper_func(**kwargs) + except nc_exc.Unauthorized: + n_client = self._novaclient_get(proj_name, True) + oper_func = getattr(n_client, oper) + return oper_func(**kwargs) + except nc_exc.NotFound: + self.logger.log( + "Error: %s %s=%s not found in project %s" + % (resource, kwargs.keys()[0], kwargs.values()[0], proj_name)) + return None + except nc_exc.NoUniqueMatch: + self.logger.log( + "Error: Multiple %s %s=%s found in project %s" + % (resource, kwargs.keys()[0], kwargs.values()[0], proj_name)) + return None + + def update_static_routes(self, si_obj): + # get service instance interface list + si_props = si_obj.get_service_instance_properties() + si_if_list = si_props.get_interface_list() + if not si_if_list: + return + + st_list = si_obj.get_service_template_refs() + fq_name = st_list[0]['to'] + st_obj = self._vnc_lib.service_template_read(fq_name=fq_name) + st_props = st_obj.get_service_template_properties() + st_if_list = st_props.get_interface_type() + + for idx in range(0, len(si_if_list)): + si_if = si_if_list[idx] + static_routes = si_if.get_static_routes() + if not static_routes: + static_routes = {'route':[]} + + # update static routes + try: + rt_fq_name = self._get_if_route_table_name( + st_if_list[idx].get_service_interface_type(), + si_obj) + rt_obj = self._vnc_lib.interface_route_table_read( + fq_name=rt_fq_name) + rt_obj.set_interface_route_table_routes(static_routes) + self._vnc_lib.interface_route_table_update(rt_obj) + except NoIdError: + pass diff --git a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py index e3e451cc065..17155ee4f0e 100644 --- a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py +++ b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py @@ -3450,12 +3450,12 @@ def port_delete(self, port_id): id=iip_back_ref['uuid']) # in case of shared ip only delete the link to the VMI - if len(iip_obj.name.split(' ')) > 1: - iip_obj.del_virtual_machine_interface(port_obj) - self._instance_ip_update(iip_obj) - else: + iip_obj.del_virtual_machine_interface(port_obj) + if not iip_obj.get_virtual_machine_interface_refs(): self._instance_ip_delete( instance_ip_id=iip_back_ref['uuid']) + else: + self._instance_ip_update(iip_obj) # disassociate any floating IP used by instance fip_back_refs = getattr(port_obj, 'floating_ip_back_refs', None)