OVS detection plugin modification

Modify detection for ovs. Make log more detailed during process
detection. Get nova_region_name from DEFAULT section if
region_name is not defined in nova section.

Change-Id: I13e6d15dafe0f30de2c51942ce03317cc74fbd09
This commit is contained in:
Artur Basiak 2016-06-23 07:51:21 +02:00
parent 0a3701fffd
commit 0df8e9c268
2 changed files with 124 additions and 96 deletions

View File

@ -47,6 +47,29 @@ class Ovs(monasca_setup.detection.Plugin):
"""
def _detect(self):
process_exist = (monasca_setup.detection.
find_process_cmdline('neutron-openvsw'))
has_dependencies = self.dependencies_installed()
neutron_conf = self.get_ovs_config_file() if process_exist else ''
self.available = (process_exist is not None and
os.path.isfile(neutron_conf) and has_dependencies)
if not self.available:
if not process_exist:
log.error('OVS daemon process does not exist.')
elif not neutron_conf:
log.error(('OVS daemon process exists but configuration'
'file was not found. Path to file does not exist'
'as a process parameter or was not '
'passed via args.'))
elif not has_dependencies:
log.error(('OVS daemon process exists but required '
'dependence python-neutronclient is '
'not installed.'))
else:
self.neutron_conf = neutron_conf
def get_ovs_config_file(self):
neutron_conf = None
if self.args:
for arg in self.args:
@ -61,112 +84,110 @@ class Ovs(monasca_setup.detection.Plugin):
proc_dict = proc.as_dict()
if proc_dict['name'] == 'neutron-openvsw':
cmd = proc_dict['cmdline']
neutron_config_params = [param for param in cmd if 'neutron.conf' in param]
neutron_config_params = [param for param in cmd if
'neutron.conf' in param]
if not neutron_config_params:
continue
if '=' in neutron_config_params[0]:
neutron_conf = neutron_config_params[0].split('=')[1]
neutron_conf = neutron_config_params[0].split('=')[
1]
else:
neutron_conf = neutron_config_params[0]
except (IOError, psutil.NoSuchProcess):
# Process has already terminated, ignore
continue
if (neutron_conf is not None and os.path.isfile(neutron_conf)):
self.available = True
self.neutron_conf = neutron_conf
else:
log.error("Neutron configuration file not found!!!")
return neutron_conf
def build_config(self):
"""Build the config as a Plugins object and return.
"""
config = monasca_setup.agent_config.Plugins()
if self.dependencies_installed():
neutron_cfg = ConfigParser.SafeConfigParser()
log.info("\tUsing neutron configuration file {0}".format(self.neutron_conf))
neutron_cfg.read(self.neutron_conf)
cfg_needed = {'admin_user': 'admin_user',
'admin_password': 'admin_password',
'admin_tenant_name': 'admin_tenant_name'}
cfg_section = 'keystone_authtoken'
neutron_cfg = ConfigParser.SafeConfigParser()
log.info("\tUsing neutron configuration file {0}".format(self.neutron_conf))
neutron_cfg.read(self.neutron_conf)
cfg_needed = {'admin_user': 'admin_user',
'admin_password': 'admin_password',
'admin_tenant_name': 'admin_tenant_name'}
cfg_section = 'keystone_authtoken'
# Handle Devstack's slightly different neutron.conf names
if (
neutron_cfg.has_option(cfg_section, 'username') and
neutron_cfg.has_option(cfg_section, 'password') and
neutron_cfg.has_option(cfg_section, 'project_name')):
cfg_needed = {'admin_user': 'username',
'admin_password': 'password',
'admin_tenant_name': 'project_name'}
# Handle Devstack's slightly different neutron.conf names
if (
neutron_cfg.has_option(cfg_section, 'username') and
neutron_cfg.has_option(cfg_section, 'password') and
neutron_cfg.has_option(cfg_section, 'project_name')):
cfg_needed = {'admin_user': 'username',
'admin_password': 'password',
'admin_tenant_name': 'project_name'}
# Start with plugin-specific configuration parameters
init_config = {'cache_dir': cache_dir,
'neutron_refresh': neutron_refresh,
'ovs_cmd': ovs_cmd,
'network_use_bits': network_use_bits,
'included_interface_re': included_interface_re,
'use_absolute_metrics': use_absolute_metrics,
'use_rate_metrics': use_rate_metrics,
'use_health_metrics': use_health_metrics}
# Start with plugin-specific configuration parameters
init_config = {'cache_dir': cache_dir,
'neutron_refresh': neutron_refresh,
'ovs_cmd': ovs_cmd,
'network_use_bits': network_use_bits,
'included_interface_re': included_interface_re,
'use_absolute_metrics': use_absolute_metrics,
'use_rate_metrics': use_rate_metrics,
'use_health_metrics': use_health_metrics}
for option in cfg_needed:
init_config[option] = neutron_cfg.get(cfg_section, cfg_needed[option])
for option in cfg_needed:
init_config[option] = neutron_cfg.get(cfg_section, cfg_needed[option])
uri_version = 'v2.0'
if neutron_cfg.has_option(cfg_section, 'auth_version'):
uri_version = str(neutron_cfg.get(cfg_section, 'auth_version'))
uri_version = 'v2.0'
if neutron_cfg.has_option(cfg_section, 'auth_version'):
uri_version = str(neutron_cfg.get(cfg_section, 'auth_version'))
# Create an identity URI (again, slightly different for Devstack)
if neutron_cfg.has_option(cfg_section, 'auth_url'):
if re.match(uri_version_re, str(neutron_cfg.get(cfg_section, 'auth_url'))):
uri_version = ''
init_config['identity_uri'] = "{0}/{1}".format(neutron_cfg.get(cfg_section, 'auth_url'), uri_version)
else:
init_config['identity_uri'] = "{0}/{1}".format(neutron_cfg.get(cfg_section, 'identity_uri'), uri_version)
# Create an identity URI (again, slightly different for Devstack)
if neutron_cfg.has_option(cfg_section, 'auth_url'):
if re.match(uri_version_re, str(neutron_cfg.get(cfg_section, 'auth_url'))):
uri_version = ''
init_config['identity_uri'] = "{0}/{1}".format(neutron_cfg.get(cfg_section, 'auth_url'), uri_version)
else:
init_config['identity_uri'] = "{0}/{1}".format(neutron_cfg.get(cfg_section, 'identity_uri'), uri_version)
# Create an region_name (again, slightly different for Devstack)
if neutron_cfg.has_option('service_auth', 'region'):
init_config['region_name'] = str(neutron_cfg.get('service_auth', 'region'))
else:
# Create an region_name (again, slightly different for Devstack)
if neutron_cfg.has_option('service_auth', 'region'):
init_config['region_name'] = str(neutron_cfg.get('service_auth', 'region'))
else:
try:
init_config['region_name'] = str(neutron_cfg.get('nova', 'region_name'))
# Handle monasca-setup detection arguments, which take precedence
if self.args:
for arg in self.args:
if arg in acceptable_args and arg not in ignorable_args:
if arg == 'included_interface_re':
try:
re.compile(self.args[arg])
except re.error as e:
exception_msg = (
"Invalid regular expression given for "
"'included_interface_re'. {0}.".format(e))
log.exception(exception_msg)
raise Exception(exception_msg)
except ConfigParser.NoOptionError:
log.debug(('Option region_name was not found in nova '
'section, nova_region_name option from '
'DEFAULT section will be used.'))
init_config['region_name'] = str(neutron_cfg.get('DEFAULT',
'nova_region_name'))
init_config[arg] = self.literal_eval(self.args[arg])
elif arg in ignorable_args:
log.warn("Argument '{0}' is ignored; Fetching {0} from "
"neutron configuration file.".format(arg))
else:
log.warn("Invalid argument '{0}' "
"has been provided!!!".format(arg))
# Handle monasca-setup detection arguments, which take precedence
if self.args:
for arg in self.args:
if arg in acceptable_args and arg not in ignorable_args:
if arg == 'included_interface_re':
try:
re.compile(self.args[arg])
except re.error as e:
exception_msg = (
"Invalid regular expression given for "
"'included_interface_re'. {0}.".format(e))
log.exception(exception_msg)
raise Exception(exception_msg)
config['ovs'] = {'init_config': init_config,
'instances': []}
init_config[arg] = self.literal_eval(self.args[arg])
elif arg in ignorable_args:
log.warn("Argument '{0}' is ignored; Fetching {0} from "
"neutron configuration file.".format(arg))
else:
log.warn("Invalid argument '{0}' "
"has been provided!!!".format(arg))
config['ovs'] = {'init_config': init_config,
'instances': []}
return config
def dependencies_installed(self):
try:
import monasca_agent.collector.virt.inspector
import neutronclient.v2_0.client
except ImportError as e:
exception_msg = (
"Dependencies not satisfied; Plugin not "
"configured. {0}.".format(e))
log.exception(exception_msg)
raise Exception(exception_msg)
except ImportError:
return False
return True

View File

@ -19,11 +19,18 @@ LOG = logging.getLogger('monasca_setup.detection.plugins.ovs')
class ps_util_get_proc:
cmdLine = ['/etc/neutron/neutron.conf']
detect_warning = False
def as_dict(self):
return {'name': 'neutron-openvsw',
'cmdline': ps_util_get_proc.cmdLine}
def cmdline(self):
if not ps_util_get_proc.detect_warning:
return ['neutron-openvsw',
ps_util_get_proc.cmdLine[0]]
else:
return ['/opt/fake.txt']
class TestOvs(unittest.TestCase):
@ -42,8 +49,10 @@ class TestOvs(unittest.TestCase):
with contextlib.nested(
patch.object(psutil, 'process_iter',
return_value=[ps_util_get_proc()]),
patch.object(os.path, 'isfile', return_value=True)) as (
mock_process_iter, mock_isfile):
patch.object(os.path, 'isfile', return_value=True),
patch.object(ovs_obj, 'dependencies_installed',
return_value=True)) as (
mock_process_iter, mock_isfile, dependencies):
ovs_obj._detect()
self.assertTrue(mock_process_iter.called)
if not ps_util_get_proc.cmdLine:
@ -53,17 +62,13 @@ class TestOvs(unittest.TestCase):
with patch.object(ConfigParser, 'SafeConfigParser') as mock_config_parser:
config_parser_obj = mock_config_parser.return_value
with contextlib.nested(
patch.object(Ovs, 'dependencies_installed',
return_value=dependencies_installed),
patch.object(LOG, 'info'),
patch.object(config_parser_obj, 'has_option',
side_effect=self.has_option),
patch.object(config_parser_obj, 'get',
side_effect=self.get_value)) as (
mock_dependencies_installed, mock_log_info,
mock_has_option, mock_get):
mock_log_info, mock_has_option, mock_get):
result = ovs_obj.build_config()
self.assertTrue(mock_dependencies_installed.called)
if dependencies_installed:
self.assertTrue(mock_log_info.called)
self.assertTrue(mock_has_option.called)
@ -74,9 +79,6 @@ class TestOvs(unittest.TestCase):
else:
self.assertIn(str(('service_auth', 'region')),
str(mock_get.call_args_list[-1]))
else:
self.assertFalse(mock_log_info.called)
self.assertFalse(mock_has_option.called)
return result
def _build_config_with_arg(self, ovs_obj):
@ -139,7 +141,7 @@ class TestOvs(unittest.TestCase):
def test_detect_warning(self):
with patch.object(LOG, 'error') as mock_log_warn:
ps_util_get_proc.cmdLine = ['/opt/fake.txt']
ps_util_get_proc.detect_warning = True
self._detect(self.ovs_obj)
self.assertFalse(self.ovs_obj.available)
self.assertEqual(self.ovs_obj.neutron_conf, None)
@ -148,7 +150,13 @@ class TestOvs(unittest.TestCase):
def test_detect_conf_file_path_given(self):
self.ovs_obj.neutron_conf = None
self.ovs_obj.args = {'conf_file_path': '/opt/stack/neutron.conf'}
with patch.object(os.path, 'isfile', return_value=True) as mock_isfile:
with contextlib.nested(
patch.object(psutil, 'process_iter',
return_value=[ps_util_get_proc()]),
patch.object(os.path, 'isfile', return_value=True),
patch.object(self.ovs_obj, 'dependencies_installed',
return_value=True)) as (
mock_process_iter, mock_isfile, dependencies):
self.ovs_obj._detect()
self.assertTrue(mock_isfile.called)
self.assertTrue(self.ovs_obj.available)
@ -175,10 +183,9 @@ class TestOvs(unittest.TestCase):
self.assertEqual(result['ovs']['init_config']['included_interface_re'],
'qg.*|vhu.*|sg.*')
def test_build_config_dependencies_not_installed(self):
self.ovs_obj.neutron_conf = 'neutron-conf'
result = self._build_config(self.ovs_obj, False)
self.assertEqual(result, {})
def test_dependencies_not_installed(self):
result = self.ovs_obj.dependencies_installed()
self.assertEqual(result, False)
def test_build_config_invalid_arg_warning(self):
with patch.object(LOG, 'warn') as mock_log_warn: