Add helper for listing detailed pool information
To support automation of pool creation on a secondary Ceph cluster in a RBD Mirror setup the actor will require additional information about pools on the source cluster. Change-Id: Id88d268d42da6e453879f850ae76575ac3b0adbf
This commit is contained in:
parent
c0d3f4d246
commit
03685ca4a6
123
ceph/utils.py
123
ceph/utils.py
|
@ -2520,18 +2520,20 @@ def update_owner(path, recurse_dirs=True):
|
|||
secs=elapsed_time.total_seconds(), path=path), DEBUG)
|
||||
|
||||
|
||||
def list_pools(service):
|
||||
def list_pools(client='admin'):
|
||||
"""This will list the current pools that Ceph has
|
||||
|
||||
:param service: String service id to run under
|
||||
:returns: list. Returns a list of the ceph pools.
|
||||
:raises: CalledProcessError if the subprocess fails to run.
|
||||
:param client: (Optional) client id for ceph key to use
|
||||
Defaults to ``admin``
|
||||
:type cilent: str
|
||||
:returns: Returns a list of available pools.
|
||||
:rtype: list
|
||||
:raises: subprocess.CalledProcessError if the subprocess fails to run.
|
||||
"""
|
||||
try:
|
||||
pool_list = []
|
||||
pools = str(subprocess
|
||||
.check_output(['rados', '--id', service, 'lspools'])
|
||||
.decode('UTF-8'))
|
||||
pools = subprocess.check_output(['rados', '--id', client, 'lspools'],
|
||||
universal_newlines=True)
|
||||
for pool in pools.splitlines():
|
||||
pool_list.append(pool)
|
||||
return pool_list
|
||||
|
@ -2540,6 +2542,113 @@ def list_pools(service):
|
|||
raise
|
||||
|
||||
|
||||
def get_pool_param(pool, param, client='admin'):
|
||||
"""Get parameter from pool.
|
||||
|
||||
:param pool: Name of pool to get variable from
|
||||
:type pool: str
|
||||
:param param: Name of variable to get
|
||||
:type param: str
|
||||
:param client: (Optional) client id for ceph key to use
|
||||
Defaults to ``admin``
|
||||
:type cilent: str
|
||||
:returns: Value of variable on pool or None
|
||||
:rtype: str or None
|
||||
:raises: subprocess.CalledProcessError
|
||||
"""
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
['ceph', '--id', client, 'osd', 'pool', 'get',
|
||||
pool, param], universal_newlines=True)
|
||||
except subprocess.CalledProcessError as cp:
|
||||
if cp.returncode == 2 and 'ENOENT: option' in cp.output:
|
||||
return None
|
||||
raise
|
||||
if ':' in output:
|
||||
return output.split(':')[1].lstrip().rstrip()
|
||||
|
||||
|
||||
def get_pool_quota(pool, client='admin'):
|
||||
"""Get pool quota.
|
||||
|
||||
:param pool: Name of pool to get variable from
|
||||
:type pool: str
|
||||
:param client: (Optional) client id for ceph key to use
|
||||
Defaults to ``admin``
|
||||
:type cilent: str
|
||||
:returns: Dictionary with quota variables
|
||||
:rtype: dict
|
||||
:raises: subprocess.CalledProcessError
|
||||
"""
|
||||
output = subprocess.check_output(
|
||||
['ceph', '--id', client, 'osd', 'pool', 'get-quota', pool],
|
||||
universal_newlines=True)
|
||||
rc = re.compile(r'\s+max\s+(\S+)\s*:\s+(\d+)')
|
||||
result = {}
|
||||
for line in output.splitlines():
|
||||
m = rc.match(line)
|
||||
if m:
|
||||
result.update({'max_{}'.format(m.group(1)): m.group(2)})
|
||||
return result
|
||||
|
||||
|
||||
def get_pool_applications(pool='', client='admin'):
|
||||
"""Get pool applications.
|
||||
|
||||
:param pool: (Optional) Name of pool to get applications for
|
||||
Defaults to get for all pools
|
||||
:type pool: str
|
||||
:param client: (Optional) client id for ceph key to use
|
||||
Defaults to ``admin``
|
||||
:type cilent: str
|
||||
:returns: Dictionary with pool name as key
|
||||
:rtype: dict
|
||||
:raises: subprocess.CalledProcessError
|
||||
"""
|
||||
|
||||
cmd = ['ceph', '--id', client, 'osd', 'pool', 'application', 'get']
|
||||
if pool:
|
||||
cmd.append(pool)
|
||||
try:
|
||||
output = subprocess.check_output(cmd, universal_newlines=True)
|
||||
except subprocess.CalledProcessError as cp:
|
||||
if cp.returncode == 2 and 'ENOENT' in cp.output:
|
||||
return {}
|
||||
raise
|
||||
return json.loads(output)
|
||||
|
||||
|
||||
def list_pools_detail():
|
||||
"""Get detailed information about pools.
|
||||
|
||||
Structure:
|
||||
{'pool_name_1': {'applications': {'application': {}},
|
||||
'parameters': {'pg_num': '42', 'size': '42'},
|
||||
'quota': {'max_bytes': '1000',
|
||||
'max_objects': '10'},
|
||||
},
|
||||
'pool_name_2': ...
|
||||
}
|
||||
|
||||
:returns: Dictionary with detailed pool information.
|
||||
:rtype: dict
|
||||
:raises: subproces.CalledProcessError
|
||||
"""
|
||||
get_params = ['pg_num', 'size']
|
||||
result = {}
|
||||
applications = get_pool_applications()
|
||||
for pool in list_pools():
|
||||
result[pool] = {
|
||||
'applications': applications.get(pool, {}),
|
||||
'parameters': {},
|
||||
'quota': get_pool_quota(pool),
|
||||
}
|
||||
for param in get_params:
|
||||
result[pool]['parameters'].update({
|
||||
param: get_pool_param(pool, param)})
|
||||
return result
|
||||
|
||||
|
||||
def dirs_need_ownership_update(service):
|
||||
"""Determines if directories still need change of ownership.
|
||||
|
||||
|
|
|
@ -816,6 +816,102 @@ class CephTestCase(unittest.TestCase):
|
|||
])
|
||||
)
|
||||
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
def test_list_pools(self, _check_output):
|
||||
_check_output.return_value = 'poola\npoolb\n'
|
||||
self.assertEqual(utils.list_pools('someuser'), ['poola', 'poolb'])
|
||||
_check_output.assert_called_with(['rados', '--id', 'someuser',
|
||||
'lspools'], universal_newlines=True)
|
||||
self.assertEqual(utils.list_pools(client='someotheruser'),
|
||||
['poola', 'poolb'])
|
||||
_check_output.assert_called_with(['rados', '--id', 'someotheruser',
|
||||
'lspools'], universal_newlines=True)
|
||||
self.assertEqual(utils.list_pools(),
|
||||
['poola', 'poolb'])
|
||||
_check_output.assert_called_with(['rados', '--id', 'admin',
|
||||
'lspools'], universal_newlines=True)
|
||||
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
def test_get_pool_param(self, _check_output):
|
||||
_check_output.return_value = 'size: 3\n'
|
||||
self.assertEqual(utils.get_pool_param('rbd', 'size'), '3')
|
||||
_check_output.assert_called_with(['ceph', '--id', 'admin', 'osd',
|
||||
'pool', 'get', 'rbd', 'size'],
|
||||
universal_newlines=True)
|
||||
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
def test_get_pool_quota(self, _check_output):
|
||||
_check_output.return_value = (
|
||||
"quotas for pool 'rbd':\n"
|
||||
" max objects: N/A\n"
|
||||
" max bytes : N/A\n")
|
||||
self.assertEqual(utils.get_pool_quota('rbd'),
|
||||
{})
|
||||
_check_output.assert_called_with(['ceph', '--id', 'admin', 'osd',
|
||||
'pool', 'get-quota', 'rbd'],
|
||||
universal_newlines=True)
|
||||
_check_output.return_value = (
|
||||
"quotas for pool 'rbd':\n"
|
||||
" max objects: 10\n"
|
||||
" max bytes : N/A\n")
|
||||
self.assertEqual(utils.get_pool_quota('rbd'), {'max_objects': '10'})
|
||||
_check_output.return_value = (
|
||||
"quotas for pool 'rbd':\n"
|
||||
" max objects: N/A\n"
|
||||
" max bytes : 1000B\n")
|
||||
self.assertEqual(utils.get_pool_quota('rbd'), {'max_bytes': '1000'})
|
||||
_check_output.return_value = (
|
||||
"quotas for pool 'rbd':\n"
|
||||
" max objects: 10\n"
|
||||
" max bytes : 1000B\n")
|
||||
self.assertEqual(utils.get_pool_quota('rbd'),
|
||||
{'max_objects': '10', 'max_bytes': '1000'})
|
||||
|
||||
@patch.object(utils.subprocess, 'check_output')
|
||||
def test_get_pool_applications(self, _check_output):
|
||||
_check_output.return_value = (
|
||||
'{\n'
|
||||
' "pool": {\n'
|
||||
' "application": {}\n'
|
||||
' }\n'
|
||||
'}\n')
|
||||
self.assertEqual(utils.get_pool_applications(),
|
||||
{'pool': {'application': {}}})
|
||||
_check_output.assert_called_with(['ceph', '--id', 'admin', 'osd',
|
||||
'pool', 'application', 'get'],
|
||||
universal_newlines=True)
|
||||
utils.get_pool_applications('42')
|
||||
_check_output.assert_called_with(['ceph', '--id', 'admin', 'osd',
|
||||
'pool', 'application', 'get', '42'],
|
||||
universal_newlines=True)
|
||||
|
||||
@patch.object(utils, 'get_pool_param')
|
||||
@patch.object(utils, 'get_pool_quota')
|
||||
@patch.object(utils, 'list_pools')
|
||||
@patch.object(utils, 'get_pool_applications')
|
||||
def test_list_pools_detail(self, _get_pool_applications, _list_pools,
|
||||
_get_pool_quota, _get_pool_param):
|
||||
self.assertEqual(utils.list_pools_detail(), {})
|
||||
_get_pool_applications.return_value = {'pool': {'application': {}}}
|
||||
_list_pools.return_value = ['pool', 'pool2']
|
||||
_get_pool_quota.return_value = {'max_objects': '10',
|
||||
'max_bytes': '1000'}
|
||||
_get_pool_param.return_value = '42'
|
||||
self.assertEqual(utils.list_pools_detail(),
|
||||
{'pool': {'applications': {'application': {}},
|
||||
'parameters': {'pg_num': '42',
|
||||
'size': '42'},
|
||||
'quota': {'max_bytes': '1000',
|
||||
'max_objects': '10'},
|
||||
},
|
||||
'pool2': {'applications': {},
|
||||
'parameters': {'pg_num': '42',
|
||||
'size': '42'},
|
||||
'quota': {'max_bytes': '1000',
|
||||
'max_objects': '10'},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
class CephVolumeSizeCalculatorTestCase(unittest.TestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue