Skip to content

Commit

Permalink
Fix service monitor virtual machine manager
Browse files Browse the repository at this point in the history
- Ensure delete of VMs only if find is succesful
- Fix shared instance-ip delete on VMI delete. Ensure that all
  VMIs for the instance IP are deleted before deleting instance-ip

Change-Id: I3297bf4c509d3c66dc5845664f699a771b90c008
Closes-Bug: #1333810
  • Loading branch information
rrugge committed Nov 12, 2014
1 parent c5eef87 commit 75a56bf
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 248 deletions.
2 changes: 2 additions & 0 deletions src/config/api-server/vnc_cfg_ifmap.py
Expand Up @@ -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]:
Expand Down
1 change: 1 addition & 0 deletions src/config/svc-monitor/SConscript
Expand Up @@ -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',
Expand Down
243 changes: 0 additions & 243 deletions src/config/svc-monitor/svc_monitor/instance_manager.py
Expand Up @@ -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):

Expand Down Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion src/config/svc-monitor/svc_monitor/svc_monitor.py
Expand Up @@ -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)

Expand Down

0 comments on commit 75a56bf

Please sign in to comment.