powervc-driver/neutron-powervc/powervc/neutron/client/local_os_bindings.py

286 lines
10 KiB
Python

# Copyright 2013 IBM Corp.
"""
Module to contain all of the local OS routines
"""
'''
Created on Aug 1, 2013
@author: John Kasperski
'''
from oslo_log import log as logging
from powervc.common.client import factory
from powervc.common.constants import SERVICE_TYPES
from powervc.common.constants import LOCAL_OS
from powervc.common.gettextutils import _
from powervc.neutron.client import neutron_client_bindings
from powervc.neutron.common import constants
from powervc.neutron.common import utils
from powervc.neutron.db import powervc_db_v2
from powervc.common import config as cfg
from powervc.common import messaging
LOG = logging.getLogger(__name__)
class Client(neutron_client_bindings.Client):
"""Local OS access methods"""
def __init__(self, client, agent):
if not client:
return
self.os = LOCAL_OS
self.db = powervc_db_v2.PowerVCAgentDB()
self.agent = agent
super(Client, self).__init__(client, self.os)
self._create_amqp_listeners()
# A cache to save image uuids on power.
self.power_image_cache = []
# Save nova/glance client
self.nova = None
self.glance = None
def _create_amqp_listeners(self):
"""Listen for AMQP messages from the local OS"""
LOG.debug("Enter _create_amqp_listeners(local) method")
endpoint = messaging.NotificationEndpoint(log=LOG)
endpoint.register_handler(constants.EVENT_NETWORK_CREATE,
self._handle_network_create)
endpoint.register_handler(constants.EVENT_NETWORK_UPDATE,
self._handle_network_update)
endpoint.register_handler(constants.EVENT_NETWORK_DELETE,
self._handle_network_delete)
endpoint.register_handler(constants.EVENT_SUBNET_CREATE,
self._handle_subnet_create)
endpoint.register_handler(constants.EVENT_SUBNET_UPDATE,
self._handle_subnet_update)
endpoint.register_handler(constants.EVENT_SUBNET_DELETE,
self._handle_subnet_delete)
endpoint.register_handler(constants.EVENT_PORT_CREATE,
self._handle_port_create)
endpoint.register_handler(constants.EVENT_PORT_UPDATE,
self._handle_port_update)
endpoint.register_handler(constants.EVENT_PORT_DELETE,
self._handle_port_delete)
endpoints = [
endpoint,
]
LOG.debug("Starting to listen...... ")
messaging.start_listener(cfg.AMQP_OPENSTACK_CONF,
constants.AMQP_EXCHANGE,
constants.AMQP_TOPIC,
endpoints)
LOG.debug("Exit _create_amqp_listeners(local) method")
def _handle_network_create(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
network = payload.get('network')
network_id = network.get('id')
if not utils.is_network_mappable(network):
LOG.info(_("Network %s is not mappable"), network_id)
return
db_net = self.db.get_network(local_id=network_id)
if db_net:
LOG.info(_("DB entry for network %s already exists"), network_id)
return
self.agent.queue_event(self.os, event_type, network)
def _handle_network_update(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
network = payload.get('network')
self.agent.queue_event(self.os, event_type, network)
def _handle_network_delete(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
network_id = payload.get('network_id')
self.agent.queue_event(self.os, event_type, network_id)
def _handle_subnet_create(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
subnet = payload.get('subnet')
subnet_id = subnet.get('id')
if not utils.is_subnet_mappable(subnet):
LOG.info(_("Subnet %s is not mappable"), subnet_id)
return
db_sub = self.db.get_subnet(local_id=subnet_id)
if db_sub:
LOG.info(_("DB entry for subnet %s already exists"), subnet_id)
return
self.agent.queue_event(self.os, event_type, subnet)
def _handle_subnet_update(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
subnet = payload.get('subnet')
self.agent.queue_event(self.os, event_type, subnet)
def _handle_subnet_delete(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
subnet_id = payload.get('subnet_id')
self.agent.queue_event(self.os, event_type, subnet_id)
def _handle_port_create(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
port = payload.get('port')
port_id = port.get('id')
if not utils.is_port_mappable(port):
LOG.info(_("Port %s is not mappable"), port_id)
return
db_port = self.db.get_port(local_id=port_id)
if db_port:
LOG.info(_("DB entry for port %s already exists"), port_id)
return
self.agent.queue_event(self.os, event_type, port)
def _handle_port_update(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
port = payload.get('port')
self.agent.queue_event(self.os, event_type, port)
def _handle_port_delete(self,
context=None,
ctxt=None,
event_type=None,
payload=None):
port_id = payload.get('port_id')
self.agent.queue_event(self.os, event_type, port_id)
def get_power_vm_mapping(self):
"""
Return dict with PowerVC to local instance uuid mappings
"""
vm_map = {}
if not self.nova:
self.nova = factory.LOCAL.get_client(str(SERVICE_TYPES.compute))
try:
local_instances = self.nova.manager.list_all_servers()
except Exception as e:
LOG.exception(_("Exception occurred getting servers: %s"), e)
return vm_map
for inst in local_instances:
metadata = inst._info.get(constants.METADATA)
if metadata:
pvc_id = metadata.get(constants.PVC_ID)
if pvc_id:
vm_map[pvc_id] = inst._info.get('id')
return vm_map
def is_instance_valid(self, uuid):
"""
Check if this VM instance is still valid. Call nova client
to retrieve the VM information.
"""
# Verify uuid is valid
if not uuid or len(uuid) == 0:
return False
# Check to see if this is a reserved port that we created while we
# are waiting for the PowerVC side to go away
if uuid.startswith(constants.RSVD_PORT_PREFIX)\
or uuid == constants.POWERVC_LOCKDEVICE_ID:
return False
if not self.nova:
self.nova = factory.LOCAL.get_client(str(SERVICE_TYPES.compute))
try:
inst = self.nova.manager.get(uuid)
except Exception as e:
"""
If the instance can not be found, exception will be thrown. These
exceptions should be caught and not break the agent.
"""
LOG.exception(_("Exception occurred getting server %s: %s"),
uuid, e)
return False
if inst:
return True
return False
def is_instance_on_power(self, uuid):
"""
Return True if an instance is hosted on power.
"""
# Verify uuid is valid
if not uuid or len(uuid) == 0:
return False
if not self.nova:
self.nova = factory.LOCAL.get_client(str(SERVICE_TYPES.compute))
try:
inst = self.nova.manager.get(uuid)
except Exception as e:
"""
If the instance can not be found, exception will be thrown. These
exceptions should be caught and not break the agent.
"""
LOG.exception(_("Exception occurred getting server %s: %s"),
uuid, e)
return False
if inst:
metadata = inst._info[constants.METADATA]
if constants.PVC_ID in metadata:
# Return true if we have pvc_id for this instance.
return True
else:
img_uuid = inst.image.get('id', '')
if img_uuid in self.power_image_cache:
return True
else:
# Check if the image is hosted on power.
if not self.glance:
self.glance = factory.LOCAL.\
get_client(str(SERVICE_TYPES.image))
try:
img = self.glance.getImage(img_uuid)
except Exception as e:
LOG.exception(_("Exception occurred getting image "
"%s: %s"), img_uuid, e)
return False
if constants.POWERVM == img.get(constants.HYPERVISOR_TYPE,
''):
self.power_image_cache.append(img_uuid)
return True
return False
# Return false if we can't find this instance locally.
return False