Stig Telfer 2099661acb Ceph plugin detects client.admin keyring
In standard system locations, check for the client.admin key
for each detected Ceph cluster and conditionally suppress
Ceph agent checks that require it if it is not found.

Change-Id: If3a28ceb5cdde40749d077ad465054eba37c848c
Story: 2005172
2019-03-08 17:19:00 +00:00

254 lines
9.4 KiB
Python

# 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.
import mock
from oslotest import base
import psutil
from monasca_setup.detection.plugins import ceph
MON_PROCESSES = [
{'name': 'ceph-mon.mon0',
'type': 'ceph-mon',
'search_string': [
'/usr/bin/ceph-mon --cluster ceph --id mon0 -f',
'/usr/bin/ceph-mon --cluster ceph -f --id mon0',
'/usr/bin/ceph-mon --id mon0 --cluster ceph -f',
'/usr/bin/ceph-mon --id mon0 -f --cluster ceph',
'/usr/bin/ceph-mon -f --cluster ceph --id mon0',
'/usr/bin/ceph-mon -f --id mon0 --cluster ceph'
]},
{'name': 'ceph1-mon.mon0',
'type': 'ceph-mon',
'search_string': [
'/usr/bin/ceph-mon --cluster ceph1 --id mon0 -f',
'/usr/bin/ceph-mon --cluster ceph1 -f --id mon0',
'/usr/bin/ceph-mon --id mon0 --cluster ceph1 -f',
'/usr/bin/ceph-mon --id mon0 -f --cluster ceph1',
'/usr/bin/ceph-mon -f --cluster ceph1 --id mon0',
'/usr/bin/ceph-mon -f --id mon0 --cluster ceph1'
]},
]
RGW_PROCESSES = [
{'name': 'ceph-radosgw.rgw0',
'type': 'ceph-radosgw',
'search_string': [
'/usr/bin/radosgw --cluster ceph --name client.rgw.rgw0 -f',
'/usr/bin/radosgw --cluster ceph -f --name client.rgw.rgw0',
'/usr/bin/radosgw --name client.rgw.rgw0 --cluster ceph -f',
'/usr/bin/radosgw --name client.rgw.rgw0 -f --cluster ceph',
'/usr/bin/radosgw -f --cluster ceph --name client.rgw.rgw0',
'/usr/bin/radosgw -f --name client.rgw.rgw0 --cluster ceph'
]},
{'name': 'ceph1-radosgw.rgw0',
'type': 'ceph-radosgw',
'search_string': [
'/usr/bin/radosgw --cluster ceph1 --name client.rgw.rgw0 -f',
'/usr/bin/radosgw --cluster ceph1 -f --name client.rgw.rgw0',
'/usr/bin/radosgw --name client.rgw.rgw0 --cluster ceph1 -f',
'/usr/bin/radosgw --name client.rgw.rgw0 -f --cluster ceph1',
'/usr/bin/radosgw -f --cluster ceph1 --name client.rgw.rgw0',
'/usr/bin/radosgw -f --name client.rgw.rgw0 --cluster ceph1'
]},
]
def mocked_service_config(*args, **kwargs):
if args[1] == 'mon':
return MON_PROCESSES
elif args[1] == 'radosgw':
return RGW_PROCESSES
return []
class FakeProcess(object):
cmdLine = None
def as_dict(self, attrs=None):
all_attrs = {'name': 'ceph',
'exe': FakeProcess.exe(),
'cmdline': FakeProcess.cmdline()}
if attrs:
for key in attrs:
if key not in all_attrs:
all_attrs.pop(key, None)
return all_attrs
@staticmethod
def exe():
line = FakeProcess.cmdLine
if not line:
return None
return line[0]
@staticmethod
def cmdline():
return FakeProcess.cmdLine
class TestCephDetection(base.BaseTestCase):
CLUSTERS = [
{
'cluster_name': 'ceph',
'config_file': '/etc/ceph/ceph.conf'
},
{
'cluster_name': 'ceph1',
'config_file': '/etc/ceph/ceph1.conf'
},
]
def setUp(self):
super(TestCephDetection, self).setUp()
with mock.patch.object(ceph.Ceph, '_detect') as mock_detect:
self._ceph = ceph.Ceph('ceph')
self.assertTrue(mock_detect.called)
def test_should_not_configure_if_no_process(self):
FakeProcess.cmdLine = []
self._detect(proc=True)
self.assertFalse(self._ceph.available)
def test_should_be_available_if_everything_matches(self):
ceph_cmd = '/usr/bin/ceph-mon -f --cluster ceph --id mon0 --setuser' \
' ceph --setgroup ceph'
FakeProcess.cmdLine = [ceph_cmd]
self._detect()
self.assertTrue(self._ceph.available)
def test_build_search_string(self):
executable = '/usr/bin/ceph-mon'
args = ['--cluster ceph', '--id mon0', '-f']
expected_strings = [
'/usr/bin/ceph-mon --cluster ceph --id mon0 -f',
'/usr/bin/ceph-mon --cluster ceph -f --id mon0',
'/usr/bin/ceph-mon --id mon0 --cluster ceph -f',
'/usr/bin/ceph-mon --id mon0 -f --cluster ceph',
'/usr/bin/ceph-mon -f --cluster ceph --id mon0',
'/usr/bin/ceph-mon -f --id mon0 --cluster ceph'
]
search_strings = self._ceph._build_search_string(executable, args)
self.assertEqual(expected_strings, search_strings)
@mock.patch('os.path.exists', return_value=True)
@mock.patch('os.listdir', return_value=['ceph-mon0', 'ceph1-mon0'])
def test_service_config(self, list_dir, path_exists):
processes = self._ceph._service_config(self.CLUSTERS, 'mon')
self.assertEqual(MON_PROCESSES, processes)
@mock.patch('os.path.exists', return_value=True)
@mock.patch('os.listdir', return_value=['ceph-rgw.rgw0', 'ceph1-rgw.rgw0'])
def test_radosgw_service_config(self, list_dir, path_exists):
processes = self._ceph._service_config(self.CLUSTERS, 'radosgw')
self.assertEqual(RGW_PROCESSES, processes)
@mock.patch('os.path.exists', return_value=True)
@mock.patch('os.listdir', return_value=[])
def test_build_config_with_no_ceph_conf(self, list_dir, path_exists):
config = self._ceph.build_config()
self.assertEqual({}, dict(config))
@mock.patch('os.path.exists', return_value=True)
@mock.patch('os.listdir', return_value=['ceph.conf', 'ceph1.conf'])
def test_build_config_with_no_admin_key(self, list_dir, path_exists):
self._ceph._service_config = mock.Mock(
side_effect=mocked_service_config)
processes = MON_PROCESSES + RGW_PROCESSES
process_instances = list()
for p in processes:
instance = {
'exact_match': False,
'search_string': p['search_string'],
'detailed': True,
'name': p['name'],
'dimensions': {'component': p['type'], 'service': 'ceph'}
}
process_instances.append(instance)
expected_config = {
'process': {
'init_config': None,
'instances': process_instances,
},
'ceph': {
'init_config': None,
'instances': [{'cluster_name': 'ceph',
'collect_mon_metrics': False,
'collect_osd_metrics': False,
'collect_pool_metrics': False,
'collect_stats_metrics': False,
'collect_usage_metrics': False},
{'cluster_name': 'ceph1',
'collect_mon_metrics': False,
'collect_osd_metrics': False,
'collect_pool_metrics': False,
'collect_stats_metrics': False,
'collect_usage_metrics': False}]
}
}
config = self._ceph.build_config()
self.assertEqual(expected_config, dict(config))
@mock.patch('os.path.exists', return_value=True)
@mock.patch('os.listdir', return_value=['ceph.conf', 'ceph1.conf', 'ceph1.client.admin.keyring'])
def test_build_config(self, list_dir, path_exists):
self._ceph._service_config = mock.Mock(
side_effect=mocked_service_config)
processes = MON_PROCESSES + RGW_PROCESSES
process_instances = list()
for p in processes:
instance = {
'exact_match': False,
'search_string': p['search_string'],
'detailed': True,
'name': p['name'],
'dimensions': {'component': p['type'], 'service': 'ceph'}
}
process_instances.append(instance)
expected_config = {
'process': {
'init_config': None,
'instances': process_instances,
},
'ceph': {
'init_config': None,
'instances': [{'cluster_name': 'ceph',
'collect_mon_metrics': False,
'collect_osd_metrics': False,
'collect_pool_metrics': False,
'collect_stats_metrics': False,
'collect_usage_metrics': False},
{'cluster_name': 'ceph1'}]
}
}
config = self._ceph.build_config()
self.assertEqual(expected_config, dict(config))
def _detect(self, proc=False):
self._ceph.available = False
processes = [FakeProcess()] if not proc else []
process_iter = mock.patch.object(psutil, 'process_iter',
return_value=processes)
with process_iter as mock_process_iter:
self._ceph._detect()
self.assertTrue(mock_process_iter.called)