charm-ceph-osd/unit_tests/test_actions_remove_disk.py
Luciano Lo Giudice 55720fa087 Implement the 'remove-disk' action
This new action allows users to either purge an OSD, or remove it,
opening up the possibility of recycling the previous OSD id. In
addition, this action will clean up any bcache devices that were
created in previous steps.

Change-Id: If3566031ba3f02dac0bc86938dcf9e85a66a66f0
Depends-On: Ib959e81833eb2094d02c7bdd507b1c8b7fbcd3db
func-test-pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/683
2022-03-31 18:50:22 +00:00

137 lines
5.5 KiB
Python

# Copyright 2021 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 unittest import mock
from actions import remove_disk
from test_utils import CharmTestCase
class RemoveDiskActionTests(CharmTestCase):
@mock.patch.object(remove_disk.subprocess, 'check_output')
def test_get_device_map(self, check_output):
check_output.return_value = b'''
{
"1": [{"devices": ["/dev/sdx1"]}],
"2": [{"devices": ["/dev/sdc2", "/dev/sdc3"]}]
}
'''
rv = remove_disk.get_device_map()
self.assertEqual(rv[0]['path'], '/dev/sdx1')
self.assertEqual(rv[1]['id'], rv[2]['id'])
def test_normalize_osd_id(self):
self.assertEqual('osd.1', remove_disk.normalize_osd_id(1))
self.assertEqual('osd.2', remove_disk.normalize_osd_id('osd.2'))
self.assertEqual('osd.3', remove_disk.normalize_osd_id('3'))
def test_map_device_id(self):
dev_map = [
{'id': 'osd.1', 'path': '/dev/sdc1'},
{'id': 'osd.2', 'path': '/dev/sdd2'},
{'id': 'osd.2', 'path': '/dev/sdx3'}
]
self.assertEqual(
'osd.1',
remove_disk.map_device_to_id(dev_map, '/dev/sdc1'))
self.assertIsNone(
remove_disk.map_device_to_id(dev_map, '/dev/sdx4'))
self.assertEqual(
'/dev/sdd2',
remove_disk.map_id_to_device(dev_map, 'osd.2'))
self.assertIsNone(
remove_disk.map_id_to_device(dev_map, 'osd.3'))
@mock.patch.object(remove_disk, 'get_bcache_names')
def test_action_osd_constructor(self, bcache_names):
bcache_names.return_value = ('bcache0', '/dev/bcache0')
dev_map = [
{'path': '/dev/sdx1', 'id': 'osd.1'}
]
with self.assertRaises(remove_disk.RemoveException):
remove_disk.ActionOSD(dev_map, dev='/dev/sdx1', osd_id='osd.1')
obj = remove_disk.ActionOSD(dev_map, dev='/dev/sdx1')
self.assertEqual(obj.osd_id, 'osd.1')
obj = remove_disk.ActionOSD(dev_map, osd_id='1')
self.assertEqual(obj.device, '/dev/sdx1')
@mock.patch.object(remove_disk, 'device_size')
@mock.patch.object(remove_disk.charms_ceph.utils, 'stop_osd')
@mock.patch.object(remove_disk, 'bcache_remove')
@mock.patch.object(remove_disk.subprocess, 'call')
@mock.patch.object(remove_disk.subprocess, 'check_call')
@mock.patch.object(remove_disk, 'get_bcache_names')
def test_action_osd_remove(self, get_bcache_names, check_call,
call, bcache_remove, stop_osd, device_size):
call.return_value = 0
get_bcache_names.return_value = ('/dev/backing', '/dev/caching')
device_size.side_effect = lambda x: 1 if x == '/dev/caching' else 0
dev_map = [
{'path': '/dev/bcache0', 'id': 'osd.1'}
]
prefix_args = ['ceph', '--id', 'osd-removal']
obj = remove_disk.ActionOSD(dev_map, osd_id='1')
obj.remove(True, 1, True)
call.assert_any_call(prefix_args + ['osd', 'safe-to-destroy', 'osd.1'])
check_call.assert_any_call(prefix_args + ['osd', 'purge', 'osd.1',
'--yes-i-really-mean-it'])
check_call.assert_any_call(prefix_args + ['osd', 'crush', 'reweight',
'osd.1', '0'])
bcache_remove.assert_called_with(
'/dev/bcache0', '/dev/backing', '/dev/caching')
report = obj.report
self.assertIn('/dev/backing', report)
report = report['/dev/backing']
self.assertIn('osd-ids', report)
self.assertIn('osd.1', report['osd-ids'])
self.assertIn('cache-devices', report)
self.assertIn('partition-size', report)
self.assertEqual('/dev/caching', report['cache-devices'])
self.assertEqual(1, report['partition-size'])
# Test the timeout check.
with self.assertRaises(remove_disk.RemoveException):
call.return_value = 1
obj.remove(False, 0, False)
@mock.patch.object(remove_disk.hookenv, 'local_unit')
@mock.patch.object(remove_disk.hookenv, 'action_set')
def test_write_report(self, action_set, local_unit):
output = {}
local_unit.return_value = 'ceph-osd/0'
action_set.side_effect = lambda x: output.update(x)
report = {'dev@': {'osd-ids': 'osd.1', 'cache-devices': 'cache@',
'partition-size': 5}}
remove_disk.write_report(report, 'text')
self.assertIn('message', output)
msg = output['message']
self.assertIn('juju run-action ceph-osd/0 add-disk', msg)
self.assertIn('osd-devices=dev@', msg)
self.assertIn('osd-ids=osd.1', msg)
self.assertIn('cache-devices=cache@', msg)
self.assertIn('partition-size=5', msg)
def test_make_same_length(self):
l1, l2 = [1], []
remove_disk.make_same_length(l1, l2)
self.assertEqual(len(l1), len(l2))
self.assertIsNone(l2[0])
prev_len = len(l1)
remove_disk.make_same_length(l1, l2)
self.assertEqual(len(l1), prev_len)