Add get-health action to the Ceph mon charm

* get-health - outputs `ceph health` output

Including unit and functional tests for the above actions.

Change-Id: Id4c0a89f2068a6f30025d4a165f84ad112b62cf7
Closes-Bug: #1720099
This commit is contained in:
James Hebden 2017-12-04 12:48:41 +11:00
parent 91d6885e50
commit 001ac4786f
6 changed files with 134 additions and 1 deletions

View File

@ -2,6 +2,8 @@ pause-health:
description: Pause ceph health operations across the entire ceph cluster
resume-health:
description: Resume ceph health operations across the entire ceph cluster
get-health:
description: Output the current cluster health reported by `ceph health`
create-cache-tier:
description: Create a new cache tier
params:

View File

@ -13,11 +13,11 @@
# limitations under the License.
from subprocess import CalledProcessError, check_output
import rados
import sys
sys.path.append('hooks')
import rados
from charmhelpers.core.hookenv import log, action_get, action_fail
from charmhelpers.contrib.storage.linux.ceph import pool_set, \
set_pool_quota, snapshot_pool, remove_pool_snapshot
@ -25,6 +25,7 @@ from charmhelpers.contrib.storage.linux.ceph import pool_set, \
# Connect to Ceph via Librados and return a connection
def connect():
"""Creates a connection to Ceph using librados."""
try:
cluster = rados.Rados(conffile='/etc/ceph/ceph.conf')
cluster.connect()
@ -38,11 +39,13 @@ def connect():
def create_crush_rule():
"""Stub function."""
# Shell out
pass
def list_pools():
"""Return a list of all Ceph pools."""
try:
cluster = connect()
pool_list = cluster.list_pools()
@ -56,7 +59,31 @@ def list_pools():
action_fail(str(e))
def get_health():
"""
Returns the output of 'ceph health'.
On error, 'unknown' is returned.
"""
try:
value = check_output(['ceph', 'health'])
return value
except CalledProcessError as e:
action_fail(e.message)
return 'Getting health failed, health unknown'
def pool_get():
"""
Returns a key from a pool using 'ceph osd pool get'.
The key is provided via the 'key' action parameter and the
pool provided by the 'pool_name' parameter. These are used when
running 'ceph osd pool get <pool_name> <key>', the result of
which is returned.
On failure, 'unknown' will be returned.
"""
key = action_get("key")
pool_name = action_get("pool_name")
try:
@ -65,9 +92,18 @@ def pool_get():
return value
except CalledProcessError as e:
action_fail(str(e))
return 'unknown'
def set_pool():
"""
Sets an arbitrary key key in a Ceph pool.
Sets the key specified by the action parameter 'key' to the value
specified in the action parameter 'value' for the pool specified
by the action parameter 'pool_name' using the charmhelpers
'pool_set' function.
"""
key = action_get("key")
value = action_get("value")
pool_name = action_get("pool_name")
@ -75,6 +111,11 @@ def set_pool():
def pool_stats():
"""
Returns statistics for a pool.
The pool name is provided by the action parameter 'pool-name'.
"""
try:
pool_name = action_get("pool-name")
cluster = connect()
@ -93,6 +134,13 @@ def pool_stats():
def delete_pool_snapshot():
"""
Delete a pool snapshot.
Deletes a snapshot from the pool provided by the action
parameter 'pool-name', with the snapshot name provided by
action parameter 'snapshot-name'
"""
pool_name = action_get("pool-name")
snapshot_name = action_get("snapshot-name")
remove_pool_snapshot(service='ceph',
@ -102,6 +150,13 @@ def delete_pool_snapshot():
# Note only one or the other can be set
def set_pool_max_bytes():
"""
Sets the max bytes quota for a pool.
Sets the pool quota maximum bytes for the pool specified by
the action parameter 'pool-name' to the value specified by
the action parameter 'max'
"""
pool_name = action_get("pool-name")
max_bytes = action_get("max")
set_pool_quota(service='ceph',
@ -110,6 +165,13 @@ def set_pool_max_bytes():
def snapshot_ceph_pool():
"""
Snapshots a Ceph pool.
Snapshots the pool provided in action parameter 'pool-name' and
uses the parameter provided in the action parameter 'snapshot-name'
as the name for the snapshot.
"""
pool_name = action_get("pool-name")
snapshot_name = action_get("snapshot-name")
snapshot_pool(service='ceph',

6
actions/get-health Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/python
from ceph_ops import get_health
if __name__ == '__main__':
get_health()

View File

@ -708,6 +708,14 @@ class CephBasicDeployment(OpenStackAmuletDeployment):
if ret:
amulet.raise_status(amulet.FAIL, msg=ret)
def test_414_get_health_action(self):
"""Verify that getting health works"""
u.log.debug("Testing get-health")
sentry_unit = self.ceph0_sentry
action_id = u.run_action(sentry_unit, 'get-health')
assert u.wait_on_action(action_id), "HEALTH_OK"
def test_499_ceph_cmds_exit_zero(self):
"""Check basic functionality of ceph cli commands against
all ceph units."""

View File

@ -16,3 +16,4 @@ import sys
sys.path.append('hooks')
sys.path.append('lib')
sys.path.append('unit_tests')
sys.path.append('actions')

View File

@ -0,0 +1,54 @@
# Copyright 2016 Canonical Ltd
#
# 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.
from mock import mock
import sys
from test_utils import CharmTestCase
# python-apt is not installed as part of test-requirements but is imported by
# some charmhelpers modules so create a fake import.
mock_apt = mock.MagicMock()
sys.modules['apt'] = mock_apt
mock_apt.apt_pkg = mock.MagicMock()
# mocking for rados
mock_rados = mock.MagicMock()
sys.modules['rados'] = mock_rados
mock_rados.connect = mock.MagicMock()
# mocking for psutil
mock_psutil = mock.MagicMock()
sys.modules['psutil'] = mock_psutil
mock_psutil.disks = mock.MagicMock()
with mock.patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
lambda *args, **kwargs: f(*args, **kwargs))
# import health actions as actions
import ceph_ops as actions
class OpsTestCase(CharmTestCase):
def setUp(self):
super(OpsTestCase, self).setUp(
actions, ["check_output",
"action_get",
"action_fail",
"open"])
def test_get_health(self):
actions.get_health()
cmd = ['ceph', 'health']
self.check_output.assert_called_once_with(cmd)