185 lines
7.1 KiB
Python
185 lines
7.1 KiB
Python
# Copyright 2014 Cisco Systems, Inc.
|
|
# 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.
|
|
#
|
|
|
|
|
|
from keystoneclient.v3 import client
|
|
from oslo.config import cfg
|
|
from oslo import messaging
|
|
|
|
from neutron.openstack.common import excutils
|
|
from neutron.openstack.common import log as logging
|
|
from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc
|
|
from neutron.plugins.ml2.drivers.cisco.dfa import projects_cache_db_v2
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
notif_params = {
|
|
'keystone': {
|
|
'admin_token': 'ADMIN',
|
|
'admin_endpoint': 'http://localhost:%(admin_port)s/',
|
|
'admin_port': '35357',
|
|
'default_notification_level': 'INFO',
|
|
'notification_topics': 'notifications',
|
|
'control_exchange': 'openstack',
|
|
}
|
|
}
|
|
|
|
proj_exceptions_list = [
|
|
'admin', 'service', 'invisible_to_admin', 'demo', 'alt_demo']
|
|
|
|
|
|
class NotificationEndpoint(object):
|
|
def __init__(self, evnt_hndlr):
|
|
self._event_hndlr = evnt_hndlr
|
|
|
|
def info(self, ctxt, publisher_id, event_type, payload, metadata):
|
|
self._event_hndlr.callback(event_type, payload)
|
|
|
|
|
|
class EventsHandler(projects_cache_db_v2.ProjectsInfoCache):
|
|
"""This class defines methods to listen and process the project events."""
|
|
|
|
def __init__(self, ser_name, dcnm_client):
|
|
self._keystone = None
|
|
self._service = ser_name
|
|
self._notif_params = {}
|
|
self._set_notif_params()
|
|
self._dcnm_client = dcnm_client
|
|
self.events_handler = {
|
|
'identity.project.created': self.project_create_event,
|
|
'identity.project.deleted': self.project_delete_event,
|
|
'identity.user.created': self.no_op_event,
|
|
'identity.user.deleted': self.no_op_event,
|
|
}
|
|
|
|
def no_op_event(self, keyc, project_id, dcnmc):
|
|
pass
|
|
|
|
def project_create_event(self, keyc, project_id, dcnmc):
|
|
"""Create a project on the DCNM.
|
|
|
|
:param keyc: keystoneclient object
|
|
:param project_id: UUID of the project
|
|
:param dcnmc: DCNM client object
|
|
"""
|
|
proj = keyc.projects.get(project_id)
|
|
proj_name = proj.name
|
|
desc = proj.description
|
|
LOG.debug("project_create_event: %(proj)s %(proj_name)s %(desc)s." %
|
|
{'proj': proj, 'proj_name': proj_name, 'desc': desc})
|
|
if proj_name not in proj_exceptions_list:
|
|
try:
|
|
dcnmc.create_project(proj_name, desc)
|
|
except dexc.DFAClientConnectionFailed as ex:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.exception(_('Failed to create %(proj)s. '
|
|
'Error:%(err)s.'),
|
|
{'proj': proj_name, 'err': ex})
|
|
proj_info = {'project_id': project_id,
|
|
'project_name': proj_name}
|
|
self.create_projects_cache_db(proj_info)
|
|
|
|
def project_delete_event(self, keyc, project_id, dcnmc):
|
|
"""Delete a project on the DCNM.
|
|
|
|
:param keyc: keystoneclient object
|
|
:param project_id: UUID of the project
|
|
:param dcnmc: DCNM client object
|
|
"""
|
|
try:
|
|
proj_info = self.delete_projects_cache_db(project_id)
|
|
LOG.debug("project_delete_event: proj_info: %s." % proj_info)
|
|
dcnmc.delete_tenant(proj_info.project_name)
|
|
except dexc.ProjectIdNotFound:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.exception(_("Failed to delete %(id)s"), {'id': project_id})
|
|
except dexc.DFAClientConnectionFailed:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.exception(_("Failed to delete %(proj)s in DCNM."),
|
|
{'proj': proj_info.project_name})
|
|
|
|
def _set_notif_params(self):
|
|
"""Read notification parameters from the config file."""
|
|
self._notif_params.update(notif_params[self._service])
|
|
temp_db = {}
|
|
cfgfile = cfg.find_config_files(self._service)
|
|
multi_parser = cfg.MultiConfigParser()
|
|
cfgr = multi_parser.read(cfgfile)
|
|
if len(cfgr) == 0:
|
|
LOG.error(_("Failed to read %s."), cfgfile)
|
|
return
|
|
for parsed_file in multi_parser.parsed:
|
|
for parsed_item in parsed_file.keys():
|
|
for key, value in parsed_file[parsed_item].items():
|
|
if key in self._notif_params:
|
|
val = notif_params[self._service].get(key)
|
|
if val != value[0]:
|
|
temp_db[key] = value[0]
|
|
|
|
self._notif_params.update(temp_db)
|
|
self._token = self.get_notif_params().get('admin_token')
|
|
_endpoint = self.get_notif_params().get('admin_endpoint')
|
|
self._endpoint_url = _endpoint % self.get_notif_params() + 'v3/'
|
|
self._keystone = client.Client(token=self._token,
|
|
endpoint=self._endpoint_url)
|
|
|
|
def callback(self, event_type, payload):
|
|
"""Callback method for processing events in notification queue.
|
|
|
|
:param event_type: event type in the notification queue such as
|
|
identity.project.created, identity.project.deleted.
|
|
:param payload: Contains information of an event
|
|
"""
|
|
try:
|
|
event = event_type
|
|
if event in self.events_handler:
|
|
project_id = payload['resource_info']
|
|
self.events_handler[event](self._keystone, project_id,
|
|
self._dcnm_client)
|
|
except KeyError:
|
|
LOG.error(_('event_type %s does not have payload/resource_info '
|
|
'key'), event)
|
|
|
|
def event_handler(self):
|
|
"""Prepare connection and channels for listenning to the events."""
|
|
topicname = self.get_notif_params().get('notification_topics')
|
|
transport = messaging.get_transport(cfg.CONF)
|
|
targets = [messaging.Target(topic=topicname)]
|
|
endpoints = [NotificationEndpoint(self)]
|
|
server = messaging.get_notification_listener(transport, targets,
|
|
endpoints)
|
|
server.start()
|
|
server.wait()
|
|
|
|
def get_notif_params(self):
|
|
"""Return notification parameters."""
|
|
return self._notif_params
|
|
|
|
def is_valid_project(self, project_id):
|
|
"""Check the validity of project.
|
|
|
|
:param project_id: UUID of project
|
|
:returns: True if project is valid.
|
|
"""
|
|
proj = self._keystone.projects.get(project_id)
|
|
proj_name = proj.name
|
|
if proj_name in proj_exceptions_list:
|
|
LOG.debug("Project %s is not created by user." % proj_name)
|
|
return False
|
|
return True
|