93e9885aa7
When gathering the list of local OSD ids, the charm would consider the entries under '/var/lib/ceph/osd/ceph-XXX' where 'XXX" was the OSD id. However, if an entry under that directory isn't mounted, then the OSD that would represent that entry should be discarded, as it's no longer active. This patchset thus filters those entries by looking for them in the mount points. Closes-Bug: #1934938 Change-Id: I69c6356e450cc0c96de4afe571b438d4a2ea5177
166 lines
5.7 KiB
Python
166 lines
5.7 KiB
Python
# 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.
|
|
import mock
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
from test_utils import CharmTestCase
|
|
|
|
sys.path.append('hooks')
|
|
|
|
import osd_in_out as actions
|
|
|
|
|
|
def mock_check_output(cmd, **kwargs):
|
|
action, osd_id = cmd[-2:] # get the last two arguments from cmd
|
|
return "marked {} osd.{}. \n".format(action, osd_id).encode("utf-8")
|
|
|
|
|
|
class OSDOutTestCase(CharmTestCase):
|
|
def setUp(self):
|
|
super(OSDOutTestCase, self).setUp(
|
|
actions, ["check_output",
|
|
"get_local_osd_ids",
|
|
"assess_status",
|
|
"parse_osds_arguments",
|
|
"function_fail",
|
|
"function_set"])
|
|
|
|
self.check_output.side_effect = mock_check_output
|
|
|
|
def test_osd_out(self):
|
|
self.get_local_osd_ids.return_value = ["5", "6", "7"]
|
|
self.parse_osds_arguments.return_value = {"5"}
|
|
actions.osd_out()
|
|
self.check_output.assert_called_once_with(
|
|
["ceph", "--id", "osd-upgrade", "osd", "out", "5"],
|
|
stderr=subprocess.STDOUT
|
|
)
|
|
self.assess_status.assert_called_once_with()
|
|
|
|
def test_osd_out_all(self):
|
|
self.get_local_osd_ids.return_value = ["5", "6", "7"]
|
|
self.parse_osds_arguments.return_value = {"all"}
|
|
actions.osd_out()
|
|
self.check_output.assert_has_calls(
|
|
[mock.call(
|
|
["ceph", "--id", "osd-upgrade", "osd", "out", i],
|
|
stderr=subprocess.STDOUT
|
|
) for i in set(["5", "6", "7"])])
|
|
self.assess_status.assert_called_once_with()
|
|
|
|
def test_osd_out_not_local(self):
|
|
self.get_local_osd_ids.return_value = ["5"]
|
|
self.parse_osds_arguments.return_value = {"6", "7", "8"}
|
|
actions.osd_out()
|
|
self.check_output.assert_not_called()
|
|
self.function_fail.assert_called_once_with(
|
|
"invalid ceph OSD device id: "
|
|
"{}".format(",".join(set(["6", "7", "8"]))))
|
|
self.assess_status.assert_not_called()
|
|
|
|
|
|
class OSDInTestCase(CharmTestCase):
|
|
def setUp(self):
|
|
super(OSDInTestCase, self).setUp(
|
|
actions, ["check_output",
|
|
"get_local_osd_ids",
|
|
"assess_status",
|
|
"parse_osds_arguments",
|
|
"function_fail",
|
|
"function_set"])
|
|
|
|
self.check_output.side_effect = mock_check_output
|
|
|
|
def test_osd_in(self):
|
|
self.get_local_osd_ids.return_value = ["5", "6", "7"]
|
|
self.parse_osds_arguments.return_value = {"5"}
|
|
actions.osd_in()
|
|
self.check_output.assert_called_once_with(
|
|
["ceph", "--id", "osd-upgrade", "osd", "in", "5"],
|
|
stderr=subprocess.STDOUT
|
|
)
|
|
self.assess_status.assert_called_once_with()
|
|
|
|
def test_osd_in_all(self):
|
|
self.get_local_osd_ids.return_value = ["5", "6", "7"]
|
|
self.parse_osds_arguments.return_value = {"all"}
|
|
actions.osd_in()
|
|
self.check_output.assert_has_calls(
|
|
[mock.call(
|
|
["ceph", "--id", "osd-upgrade", "osd", "in", i],
|
|
stderr=subprocess.STDOUT
|
|
) for i in set(["5", "6", "7"])])
|
|
self.assess_status.assert_called_once_with()
|
|
|
|
def test_osd_in_not_local(self):
|
|
self.get_local_osd_ids.return_value = ["5"]
|
|
self.parse_osds_arguments.return_value = {"6"}
|
|
actions.osd_in()
|
|
self.check_output.assert_not_called()
|
|
self.function_fail.assert_called_once_with(
|
|
"invalid ceph OSD device id: 6")
|
|
self.assess_status.assert_not_called()
|
|
|
|
|
|
class OSDMountTestCase(CharmTestCase):
|
|
def setUp(self):
|
|
super(OSDMountTestCase, self).setUp(actions, [])
|
|
|
|
@mock.patch('os.path.exists')
|
|
@mock.patch('os.listdir')
|
|
@mock.patch('charms_ceph.utils.filesystem_mounted')
|
|
def test_mounted_osds(self, fs_mounted, listdir, exists):
|
|
exists.return_value = True
|
|
listdir.return_value = [
|
|
'/var/lib/ceph/osd/ceph-1', '/var/lib/ceph/osd/ceph-2']
|
|
fs_mounted.side_effect = lambda x: x == listdir.return_value[0]
|
|
osds = actions.get_local_osd_ids()
|
|
self.assertIn(listdir.return_value[0][-1], osds)
|
|
self.assertNotIn(listdir.return_value[1][-1], osds)
|
|
|
|
|
|
class MainTestCase(CharmTestCase):
|
|
def setUp(self):
|
|
super(MainTestCase, self).setUp(actions, ["function_fail"])
|
|
|
|
def test_invokes_action(self):
|
|
dummy_calls = []
|
|
|
|
def dummy_action():
|
|
dummy_calls.append(True)
|
|
|
|
with mock.patch.dict(actions.ACTIONS, {"foo": dummy_action}):
|
|
actions.main(["foo"])
|
|
self.assertEqual(dummy_calls, [True])
|
|
|
|
def test_unknown_action(self):
|
|
"""Unknown actions aren't a traceback."""
|
|
exit_string = actions.main(["foo"])
|
|
self.assertEqual("Action foo undefined", exit_string)
|
|
|
|
def test_failing_action(self):
|
|
"""Actions which traceback trigger function_fail() calls."""
|
|
dummy_calls = []
|
|
|
|
self.function_fail.side_effect = dummy_calls.append
|
|
|
|
def dummy_action():
|
|
raise ValueError("uh oh")
|
|
|
|
with mock.patch.dict(actions.ACTIONS, {"foo": dummy_action}):
|
|
actions.main(["foo"])
|
|
self.assertEqual(dummy_calls, ["Action foo failed: uh oh"])
|