diff --git a/moganclient/osc/v1/server.py b/moganclient/osc/v1/server.py index 82f5346..5e70629 100644 --- a/moganclient/osc/v1/server.py +++ b/moganclient/osc/v1/server.py @@ -29,6 +29,41 @@ from moganclient.common.i18n import _ LOG = logging.getLogger(__name__) +class ServersActionBase(command.Command): + def _get_parser_with_action(self, prog_name, action): + parser = super(ServersActionBase, self).get_parser(prog_name) + parser.add_argument( + 'server', + metavar='', + nargs='+', + help=_("Baremetal server(s) to %s (name or UUID)") % action + ) + return parser + + def _action_multiple_items(self, parsed_args, action, method_name, + **kwargs): + bc_client = self.app.client_manager.baremetal_compute + result = 0 + for one_server in parsed_args.server: + try: + data = utils.find_resource( + bc_client.server, one_server) + method = getattr(bc_client.server, method_name) + method(data.uuid, **kwargs) + except Exception as e: + result += 1 + LOG.error(_("Failed to %(action)s server with name or UUID " + "'%(server)s': %(e)s") % + {'action': action, 'server': one_server, 'e': e}) + + if result > 0: + total = len(parsed_args.server) + msg = (_("%(result)s of %(total)s baremetal servers failed " + "to %(action)s.") % {'result': result, 'total': total, + 'action': action}) + raise exceptions.CommandError(msg) + + class CreateServer(command.ShowOne): """Create a new baremetal server""" @@ -330,31 +365,12 @@ class UpdateServer(command.ShowOne): return zip(*sorted(six.iteritems(info))) -class SetServerPowerState(command.Command): - """Set the power state of baremetal server""" +class StartServer(ServersActionBase): + """Start a baremetal server.""" def get_parser(self, prog_name): - parser = super(SetServerPowerState, self).get_parser(prog_name) - parser.add_argument( - 'server', - metavar='', - help=_("Baremetal server to update (name or UUID)") - ) - parser.add_argument( - "--power-state", - metavar="", - choices=['on', 'off', 'reboot'], - required=True, - help=_("Power state to be set to the baremetal server, must be " - "one of: 'on', 'off' and 'reboot'.") - ) - return parser + return self._get_parser_with_action(prog_name, 'start') def take_action(self, parsed_args): - bc_client = self.app.client_manager.baremetal_compute - server = utils.find_resource( - bc_client.server, - parsed_args.server, - ) - bc_client.server.set_power_state(server_id=server.uuid, - power_state=parsed_args.power_state) + self._action_multiple_items(parsed_args, 'start', 'set_power_state', + power_state='on') diff --git a/moganclient/tests/unit/osc/v1/test_server.py b/moganclient/tests/unit/osc/v1/test_server.py index b33c2c7..80af874 100644 --- a/moganclient/tests/unit/osc/v1/test_server.py +++ b/moganclient/tests/unit/osc/v1/test_server.py @@ -18,7 +18,6 @@ import mock import uuid from osc_lib import exceptions -from osc_lib.tests import utils as osc_test_utils from osc_lib import utils from moganclient.osc.v1 import server @@ -442,31 +441,67 @@ class TestServerShow(test_base.TestBaremetalComputeV1): self.assertEqual(expected, mock_get.call_args_list) -@mock.patch.object(utils, 'find_resource') -@mock.patch.object(server_mgr.ServerManager, '_update_all') -class TestSetServerPowerState(test_base.TestBaremetalComputeV1): +class TestServerPowerActionBase(test_base.TestBaremetalComputeV1): def setUp(self): - super(TestSetServerPowerState, self).setUp() - self.cmd = server.SetServerPowerState(self.app, None) - self.fake_server = fakes.FakeServer.create_one_server() + super(TestServerPowerActionBase, self).setUp() + self.action = None + self.action_name = None - def test_server_set_power_state(self, mock_update_all, mock_find): - mock_find.return_value = self.fake_server - args = ['--power-state', 'off', self.fake_server.uuid] - verify_args = [('power_state', 'off'), - ('server', self.fake_server.uuid)] + def _test_server_power_action_one(self, mock_update_all, mock_find): + fake_server = fakes.FakeServer.create_one_server() + mock_find.return_value = fake_server + args = [fake_server.uuid] + verify_args = [('server', [fake_server.uuid])] parsed_args = self.check_parser(self.cmd, args, verify_args) self.cmd.take_action(parsed_args) mock_update_all.assert_called_with( - '/instances/%s/states/power' % self.fake_server.uuid, - data={'target': 'off'}) + '/instances/%s/states/power' % fake_server.uuid, + data={'target': self.action}) - def test_server_set_invalid_power_state(self, - mock_update_all, mock_find): - mock_find.return_value = self.fake_server - args = ['--power-state', 'non_state', self.fake_server.uuid] - verify_args = [('power_state', 'off'), - ('server', self.fake_server.uuid)] - self.assertRaises(osc_test_utils.ParserException, - self.check_parser, - self.cmd, args, verify_args) + def _test_server_power_action_multiple(self, mock_update_all, + mock_find): + fake_servers = fakes.FakeServer.create_servers(count=3) + mock_find.side_effect = fake_servers + args = [s.name for s in fake_servers] + verify_args = [('server', [s.name for s in fake_servers])] + parsed_args = self.check_parser(self.cmd, args, verify_args) + self.cmd.take_action(parsed_args) + expected = [mock.call( + '/instances/%s/states/power' % s.uuid, + data={'target': self.action}) for s in fake_servers] + self.assertEqual(expected, mock_update_all.call_args_list) + + def _test_server_delete_more_than_one_partly_failed( + self, mock_update_all, mock_find): + fake_servers = fakes.FakeServer.create_servers(count=3) + mock_find.side_effect = fake_servers + args = [s.name for s in fake_servers] + verify_args = [('server', [s.name for s in fake_servers])] + parsed_args = self.check_parser(self.cmd, args, verify_args) + mock_update_all.side_effect = [mock.Mock(), Exception(), mock.Mock()] + exc = self.assertRaises(exceptions.CommandError, + self.cmd.take_action, parsed_args) + self.assertEqual( + '1 of 3 baremetal servers failed to %s.' % self.action_name, + str(exc)) + + +@mock.patch.object(utils, 'find_resource') +@mock.patch.object(server_mgr.ServerManager, '_update_all') +class TestServerStart(TestServerPowerActionBase): + def setUp(self): + super(TestServerStart, self).setUp() + self.cmd = server.StartServer(self.app, None) + self.action = 'on' + self.action_name = 'start' + + def test_server_start_one(self, mock_update_all, mock_find): + self._test_server_power_action_one(mock_update_all, mock_find) + + def test_server_start_multiple(self, mock_update_all, mock_find): + self._test_server_power_action_multiple(mock_update_all, mock_find) + + def test_server_start_multiple_partly_failed(self, + mock_update_all, mock_find): + self._test_server_delete_more_than_one_partly_failed( + mock_update_all, mock_find) diff --git a/setup.cfg b/setup.cfg index d6012c7..d597815 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,7 +41,7 @@ openstack.baremetal_compute.v1 = baremetal_server_delete = moganclient.osc.v1.server:DeleteServer baremetal_server_list = moganclient.osc.v1.server:ListServer baremetal_server_show = moganclient.osc.v1.server:ShowServer - baremetal_server_power = moganclient.osc.v1.server:SetServerPowerState + baremetal_server_start = moganclient.osc.v1.server:StartServer baremetal_server_update = moganclient.osc.v1.server:UpdateServer baremetal_availability_zone_list = moganclient.osc.v1.availability_zone:ListAvailabilityZone