Add monitor feature to the VIM

This patch add monitoring feature to the VIM by checking the
reachability of identity service for the corresponding VIM.

Change-Id: I25beaa5e1fd2fca87503c45d720f89d6f8156622
Closes-Bug: #1554280
This commit is contained in:
Bharath Thiruveedula 2016-05-12 16:19:13 +05:30
parent daa7bf4e8e
commit 792b1e0183
10 changed files with 147 additions and 7 deletions

View File

@ -0,0 +1,3 @@
---
features:
- Add VIM health monitor to Tacker

View File

@ -0,0 +1,35 @@
# Copyright 2016 OpenStack Foundation
#
# 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.
#
"""Add status to vims
Revision ID: 22f5385a3d3f
Revises: 5246a6bd410f
Create Date: 2016-05-12 13:29:30.615609
"""
# revision identifiers, used by Alembic.
revision = '22f5385a3d3f'
down_revision = '5f88e86b35c7'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.add_column('vims',
sa.Column('status', sa.String(255),
nullable=False, server_default=''))

View File

@ -1 +1 @@
5f88e86b35c7
22f5385a3d3f

View File

@ -33,7 +33,7 @@ from tacker import manager
VIM_ATTRIBUTES = ('id', 'type', 'tenant_id', 'name', 'description',
'placement_attr', 'shared')
'placement_attr', 'shared', 'status')
VIM_AUTH_ATTRIBUTES = ('auth_url', 'vim_project', 'password', 'auth_cred')
@ -45,6 +45,7 @@ class Vim(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
shared = sa.Column(sa.Boolean, default=True, server_default=sql.true(
), nullable=False)
vim_auth = orm.relationship('VimAuth')
status = sa.Column(sa.String(255), nullable=False)
class VimAuth(model_base.BASE, models_v1.HasId):
@ -102,7 +103,8 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
tenant_id=vim.get('tenant_id'),
name=vim.get('name'),
description=vim.get('description'),
placement_attr=vim.get('placement_attr'))
placement_attr=vim.get('placement_attr'),
status=vim.get('status'))
context.session.add(vim_db)
vim_auth_db = VimAuth(
id=str(uuid.uuid4()),
@ -153,6 +155,16 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
vim_project})
return self.get_vim(context, vim_id)
def update_vim_status(self, context, vim_id, status):
with context.session.begin(subtransactions=True):
try:
vim_db = (self._model_query(context, Vim).filter(
Vim.id == vim_id).with_lockmode('update').one())
except orm_exc.NoResultFound:
raise nfvo.VimNotFoundException(vim_id=vim_id)
vim_db.update({'status': status})
return self._make_vim_dict(vim_db)
def get_vim_by_name(self, context, vim_name, fields=None,
mask_password=True):
vim_db = self._get_by_name(context, Vim, vim_name)

View File

@ -120,6 +120,12 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True,
'default': '',
},
'status': {
'allow_post': False,
'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
},
'placement_attr': {
'allow_post': False,
'allow_put': False,

View File

@ -82,3 +82,11 @@ class VimAbstractDriver(extensions.PluginInterface):
Delete VIM sensitive information such as keys from file system or DB
"""
pass
@abc.abstractmethod
def vim_status(self, auth_url):
"""Health check for VIM
Checks the health status of VIM and return a boolean value
"""
pass

View File

@ -20,8 +20,10 @@ from keystoneclient import exceptions
from oslo_config import cfg
from oslo_log import log as logging
from tacker.agent.linux import utils as linux_utils
from tacker.common import log
from tacker.extensions import nfvo
from tacker.i18n import _LW
from tacker.nfvo.drivers.vim import abstract_vim_driver
from tacker.vm import keystone
@ -31,7 +33,18 @@ CONF = cfg.CONF
OPTS = [cfg.StrOpt('openstack', default='/etc/tacker/vim/fernet_keys',
help='Dir.path to store fernet keys.')]
# same params as we used in ping monitor driver
OPENSTACK_OPTS = [
cfg.StrOpt('count', default='1',
help=_('number of ICMP packets to send')),
cfg.StrOpt('timeout', default='1',
help=_('number of seconds to wait for a response')),
cfg.StrOpt('interval', default='1',
help=_('number of seconds to wait between packets'))
]
cfg.CONF.register_opts(OPTS, 'vim_keys')
cfg.CONF.register_opts(OPENSTACK_OPTS, 'vim_monitor')
class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver):
@ -178,3 +191,20 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver):
LOG.debug(_('VIM auth successfully stored for vim %s'), vim_id)
except IOError:
raise nfvo.VimKeyNotFoundException(vim_id=vim_id)
@log.log
def vim_status(self, auth_url):
"""Checks the VIM health status"""
vim_ip = auth_url.split("//")[-1].split(":")[0].split("/")[0]
ping_cmd = ['ping',
'-c', cfg.CONF.vim_monitor.count,
'-W', cfg.CONF.vim_monitor.timeout,
'-i', cfg.CONF.vim_monitor.interval,
vim_ip]
try:
linux_utils.execute(ping_cmd, check_exit_code=True)
return True
except RuntimeError:
LOG.warning(_LW("Cannot ping ip address: %s"), vim_ip)
return False

View File

@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import threading
import time
import uuid
from oslo_config import cfg
@ -23,6 +25,7 @@ from oslo_utils import excutils
from tacker.common import driver_manager
from tacker.common import log
from tacker.common import utils
from tacker import context as t_context
from tacker.db.nfvo import nfvo_db
LOG = logging.getLogger(__name__)
@ -37,11 +40,15 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb):
extension for providing the specified VIM information
"""
supported_extension_aliases = ['nfvo']
_lock = threading.RLock()
OPTS = [
cfg.ListOpt(
'vim_drivers', default=['openstack'],
help=_('VIM driver for launching VNFs')),
cfg.IntOpt(
'monitor_interval', default=30,
help=_('Interval to check for VIM health')),
]
cfg.CONF.register_opts(OPTS, 'nfvo_vim')
@ -50,6 +57,19 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb):
self._vim_drivers = driver_manager.DriverManager(
'tacker.nfvo.vim.drivers',
cfg.CONF.nfvo_vim.vim_drivers)
self._created_vims = dict()
context = t_context.get_admin_context()
vims = self.get_vims(context)
for vim in vims:
self._created_vims[vim["id"]] = vim
self._monitor_interval = cfg.CONF.nfvo_vim.monitor_interval
threading.Thread(target=self.__run__).start()
def __run__(self):
while(1):
time.sleep(self._monitor_interval)
for created_vim in self._created_vims.values():
self.monitor_vim(created_vim)
@log.log
def create_vim(self, context, vim):
@ -57,9 +77,14 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb):
vim_obj = vim['vim']
vim_type = vim_obj['type']
vim_obj['id'] = str(uuid.uuid4())
vim_obj['status'] = 'PENDING'
try:
self._vim_drivers.invoke(vim_type, 'register_vim', vim_obj=vim_obj)
res = super(NfvoPlugin, self).create_vim(context, vim_obj)
vim_obj["status"] = "REGISTERING"
with self._lock:
self._created_vims[res["id"]] = res
self.monitor_vim(vim_obj)
return res
except Exception:
with excutils.save_and_reraise_exception():
@ -88,4 +113,22 @@ class NfvoPlugin(nfvo_db.NfvoPluginDb):
vim_obj = self._get_vim(context, vim_id)
self._vim_drivers.invoke(vim_obj['type'], 'deregister_vim',
vim_id=vim_id)
with self._lock:
self._created_vims.pop(vim_id, None)
super(NfvoPlugin, self).delete_vim(context, vim_id)
@log.log
def monitor_vim(self, vim_obj):
vim_id = vim_obj["id"]
auth_url = vim_obj["auth_url"]
vim_status = self._vim_drivers.invoke(vim_obj['type'],
'vim_status',
auth_url=auth_url)
current_status = "REACHABLE" if vim_status else "UNREACHABLE"
if current_status != vim_obj["status"]:
status = current_status
with self._lock:
super(NfvoPlugin, self).update_vim_status(
t_context.get_admin_context(),
vim_id, status)
self._created_vims[vim_id]["status"] = status

View File

@ -37,6 +37,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.addCleanup(mock.patch.stopall)
self.context = context.get_admin_context()
self._mock_driver_manager()
mock.patch('tacker.nfvo.nfvo_plugin.NfvoPlugin.__run__').start()
self.nfvo_plugin = nfvo_plugin.NfvoPlugin()
def _mock_driver_manager(self):
@ -56,6 +57,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
name='fake_vim',
description='fake_vim_description',
type='openstack',
status='Active',
placement_attr={'regions': ['RegionOne']})
vim_auth_db = nfvo_db.VimAuth(
vim_id='6261579e-d6f3-49ad-8bc3-a9cb974778ff',
@ -78,10 +80,10 @@ class TestNfvoPlugin(db_base.SqlTestCase):
'tenant_id': 'test-project'}}
vim_type = 'openstack'
res = self.nfvo_plugin.create_vim(self.context, vim_dict)
self._driver_manager.invoke.assert_called_once_with(vim_type,
'register_vim',
vim_obj=vim_dict[
'vim'])
self._driver_manager.invoke.assert_any_call(vim_type,
'register_vim', vim_obj=vim_dict['vim'])
self._driver_manager.invoke.assert_any_call('openstack', 'vim_status',
auth_url='http://localhost:5000')
self.assertIsNotNone(res)
self.assertEqual(SECRET_PASSWORD, res['auth_cred']['password'])
self.assertIn('id', res)

View File

@ -132,6 +132,7 @@ class TestVNFMPlugin(db_base.SqlTestCase):
name='fake_vim',
description='fake_vim_description',
type='openstack',
status='Active',
placement_attr={'regions': ['RegionOne']})
vim_auth_db = nfvo_db.VimAuth(
vim_id='6261579e-d6f3-49ad-8bc3-a9cb974778ff',