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:
parent
0a3701fffd
commit
0df8e9c268
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue