[OSC] Add missing waiters

We decided to start adding the optional '--wait' argument to OSC
commands after we had some commands already implemented.

This patch adds the missing waiters to commands that were
originally implemented without, but should also include the option.

Partially-implements: bp add-waiters
Change-Id: Ib4f31747838d016da244b79d7d9be4aa8aff1a58
This commit is contained in:
Maari Tamm
2021-02-11 18:41:13 +00:00
committed by Maari Tamm
parent f5ee025ad0
commit e5e815bf09
5 changed files with 393 additions and 6 deletions

View File

@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import logging
from osc_lib.cli import parseractions from osc_lib.cli import parseractions
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
@@ -33,6 +35,8 @@ ACCESS_RULE_ATTRIBUTES = [
'properties' 'properties'
] ]
LOG = logging.getLogger(__name__)
class ShareAccessAllow(command.ShowOne): class ShareAccessAllow(command.ShowOne):
"""Create a new share access rule.""" """Create a new share access rule."""
@@ -75,6 +79,11 @@ class ShareAccessAllow(command.ShowOne):
help=_('Share access level ("rw" and "ro" access levels ' help=_('Share access level ("rw" and "ro" access levels '
'are supported). Defaults to rw.') 'are supported). Defaults to rw.')
) )
parser.add_argument(
"--wait",
action='store_true',
help=_("Wait for share access rule creation.")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -97,6 +106,17 @@ class ShareAccessAllow(command.ShowOne):
access_level=parsed_args.access_level, access_level=parsed_args.access_level,
metadata=properties metadata=properties
) )
if parsed_args.wait:
if not oscutils.wait_for_status(
status_f=share_client.share_access_rules.get,
res_id=share_access_rule['id'],
status_field='state'
):
LOG.error(_("ERROR: Share access rule is in error state."))
share_access_rule = oscutils.find_resource(
share_client.share_access_rules,
share_access_rule['id'])._info
share_access_rule.update( share_access_rule.update(
{ {
'properties': utils.format_properties( 'properties': utils.format_properties(
@@ -128,6 +148,12 @@ class ShareAccessDeny(command.Command):
metavar="<id>", metavar="<id>",
help=_('ID of the access rule to be deleted.') help=_('ID of the access rule to be deleted.')
) )
parser.add_argument(
"--wait",
action='store_true',
default=False,
help=_("Wait for share access rule deletion")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -135,12 +161,21 @@ class ShareAccessDeny(command.Command):
share = apiutils.find_resource(share_client.shares, share = apiutils.find_resource(share_client.shares,
parsed_args.share) parsed_args.share)
error = None
try: try:
share.deny(parsed_args.id) share.deny(parsed_args.id)
if parsed_args.wait:
if not oscutils.wait_for_delete(
manager=share_client.share_access_rules,
res_id=parsed_args.id):
error = _("Failed to delete share access rule with ID: %s"
% parsed_args.id)
except Exception as e: except Exception as e:
raise exceptions.CommandError( error = e
if error:
raise exceptions.CommandError(_(
"Failed to delete share access rule for share " "Failed to delete share access rule for share "
"'%s': %s" % (share, e)) "'%s': %s" % (share, error)))
class ListShareAccess(command.Lister): class ListShareAccess(command.Lister):

View File

@@ -55,6 +55,12 @@ class CreateShareSnapshot(command.ShowOne):
default=None, default=None,
help=_("Add a description to the snapshot (Optional).") help=_("Add a description to the snapshot (Optional).")
) )
parser.add_argument(
'--wait',
action='store_true',
default=False,
help=_('Wait for share snapshot creation')
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -69,6 +75,17 @@ class CreateShareSnapshot(command.ShowOne):
name=parsed_args.name or None, name=parsed_args.name or None,
description=parsed_args.description or None description=parsed_args.description or None
) )
if parsed_args.wait:
if not utils.wait_for_status(
status_f=share_client.share_snapshots.get,
res_id=share_snapshot.id,
success_status=['available']
):
LOG.error(_("ERROR: Share snapshot is in error state."))
share_snapshot = utils.find_resource(
share_client.share_snapshots,
share_snapshot.id)
share_snapshot._info.pop('links', None) share_snapshot._info.pop('links', None)
return self.dict2columns(share_snapshot._info) return self.dict2columns(share_snapshot._info)
@@ -93,6 +110,12 @@ class DeleteShareSnapshot(command.Command):
default=False, default=False,
help=_("Delete the snapshot(s) ignoring the current state.") help=_("Delete the snapshot(s) ignoring the current state.")
) )
parser.add_argument(
"--wait",
action='store_true',
default=False,
help=_("Wait for share snapshot deletion")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -110,6 +133,11 @@ class DeleteShareSnapshot(command.Command):
else: else:
share_client.share_snapshots.delete( share_client.share_snapshots.delete(
snapshot_obj) snapshot_obj)
if parsed_args.wait:
if not utils.wait_for_delete(
manager=share_client.share_snapshots,
res_id=snapshot_obj.id):
result += 1
except Exception as e: except Exception as e:
result += 1 result += 1
LOG.error(_( LOG.error(_(
@@ -466,6 +494,11 @@ class AdoptShareSnapshot(command.ShowOne):
"Set driver options as key=value pairs." "Set driver options as key=value pairs."
"(repeat option to set multiple key=value pairs)") "(repeat option to set multiple key=value pairs)")
) )
parser.add_argument(
"--wait",
action='store_true',
help=_("Wait until share snapshot is adopted")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -481,6 +514,19 @@ class AdoptShareSnapshot(command.ShowOne):
name=parsed_args.name, name=parsed_args.name,
description=parsed_args.description description=parsed_args.description
) )
if parsed_args.wait:
if not utils.wait_for_status(
status_f=share_client.share_snapshots.get,
res_id=snapshot.id,
success_status=['available'],
error_status=['manage_error', 'error']
):
LOG.error(_("ERROR: Share snapshot is in error state."))
snapshot = utils.find_resource(share_client.share_snapshots,
snapshot.id)
snapshot._info.pop('links', None) snapshot._info.pop('links', None)
return self.dict2columns(snapshot._info) return self.dict2columns(snapshot._info)
@@ -499,6 +545,11 @@ class AbandonShareSnapshot(command.Command):
nargs='+', nargs='+',
help=_("Name or ID of the snapshot(s) to be abandoned.") help=_("Name or ID of the snapshot(s) to be abandoned.")
) )
parser.add_argument(
"--wait",
action='store_true',
help=_("Wait until share snapshot is abandoned")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -511,6 +562,11 @@ class AbandonShareSnapshot(command.Command):
snapshot) snapshot)
try: try:
share_client.share_snapshots.unmanage(snapshot_obj) share_client.share_snapshots.unmanage(snapshot_obj)
if parsed_args.wait:
if not utils.wait_for_delete(
manager=share_client.share_snapshots,
res_id=snapshot_obj.id):
result += 1
except Exception as e: except Exception as e:
result += 1 result += 1
LOG.error(_( LOG.error(_(

View File

@@ -373,7 +373,7 @@ class FakeShareAccessRule(object):
'access_level': 'rw', 'access_level': 'rw',
'access_to': 'demo', 'access_to': 'demo',
'access_type': 'user', 'access_type': 'user',
'state': 'queued_to_apply', 'state': 'active',
'access_key': None, 'access_key': None,
'created_at': datetime.datetime.now().isoformat(), 'created_at': datetime.datetime.now().isoformat(),
'updated_at': None, 'updated_at': None,

View File

@@ -10,6 +10,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
from unittest import mock
from osc_lib import exceptions
from osc_lib import utils as oscutils from osc_lib import utils as oscutils
from manilaclient import api_versions from manilaclient import api_versions
@@ -58,6 +61,7 @@ class TestShareAccessCreate(TestShareAccess):
manila_fakes.FakeShareAccessRule.create_one_access_rule( manila_fakes.FakeShareAccessRule.create_one_access_rule(
attrs={"share_id": self.share.id})) attrs={"share_id": self.share.id}))
self.share.allow.return_value = self.access_rule._info self.share.allow.return_value = self.access_rule._info
self.access_rules_mock.get.return_value = self.access_rule
# Get the command object to test # Get the command object to test
self.cmd = osc_share_access_rules.ShareAccessAllow(self.app, None) self.cmd = osc_share_access_rules.ShareAccessAllow(self.app, None)
@@ -135,6 +139,64 @@ class TestShareAccessCreate(TestShareAccess):
self.assertEqual(ACCESS_RULE_ATTRIBUTES, columns) self.assertEqual(ACCESS_RULE_ATTRIBUTES, columns)
self.assertCountEqual(self.access_rule._info.values(), data) self.assertCountEqual(self.access_rule._info.values(), data)
def test_share_access_create_wait(self):
arglist = [
self.share.id,
'user',
'demo',
'--wait'
]
verifylist = [
("share", self.share.id),
("access_type", "user"),
("access_to", "demo"),
("wait", True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.shares_mock.get.assert_called_with(self.share.id)
self.share.allow.assert_called_with(
access_type="user",
access="demo",
access_level=None,
metadata={}
)
self.assertEqual(ACCESS_RULE_ATTRIBUTES, columns)
self.assertCountEqual(self.access_rule._info.values(), data)
@mock.patch('manilaclient.osc.v2.share_access_rules.LOG')
def test_share_access_create_wait_error(self, mock_logger):
arglist = [
self.share.id,
'user',
'demo',
'--wait'
]
verifylist = [
("share", self.share.id),
("access_type", "user"),
("access_to", "demo"),
("wait", True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_status', return_value=False):
columns, data = self.cmd.take_action(parsed_args)
self.shares_mock.get.assert_called_with(self.share.id)
self.share.allow.assert_called_with(
access_type="user",
access="demo",
access_level=None,
metadata={}
)
mock_logger.error.assert_called_with(
"ERROR: Share access rule is in error state.")
self.assertEqual(ACCESS_RULE_ATTRIBUTES, columns)
self.assertCountEqual(self.access_rule._info.values(), data)
class TestShareAccessDelete(TestShareAccess): class TestShareAccessDelete(TestShareAccess):
@@ -166,6 +228,47 @@ class TestShareAccessDelete(TestShareAccess):
self.share.deny.assert_called_with(self.access_rule.id) self.share.deny.assert_called_with(self.access_rule.id)
self.assertIsNone(result) self.assertIsNone(result)
def test_share_access_delete_wait(self):
arglist = [
self.share.id,
self.access_rule.id,
'--wait'
]
verifylist = [
("share", self.share.id),
("id", self.access_rule.id),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=True):
result = self.cmd.take_action(parsed_args)
self.shares_mock.get.assert_called_with(self.share.id)
self.share.deny.assert_called_with(self.access_rule.id)
self.assertIsNone(result)
def test_share_access_delete_wait_error(self):
arglist = [
self.share.id,
self.access_rule.id,
'--wait'
]
verifylist = [
("share", self.share.id),
("id", self.access_rule.id),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=False):
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args
)
class TestShareAccessList(TestShareAccess): class TestShareAccessList(TestShareAccess):

View File

@@ -71,7 +71,10 @@ class TestShareSnapshotCreate(TestShareSnapshot):
self.shares_mock.get.return_value = self.share self.shares_mock.get.return_value = self.share
self.share_snapshot = ( self.share_snapshot = (
manila_fakes.FakeShareSnapshot.create_one_snapshot()) manila_fakes.FakeShareSnapshot.create_one_snapshot(
attrs={'status': 'available'}
))
self.snapshots_mock.get.return_value = self.share_snapshot
self.snapshots_mock.create.return_value = self.share_snapshot self.snapshots_mock.create.return_value = self.share_snapshot
self.cmd = osc_share_snapshots.CreateShareSnapshot(self.app, None) self.cmd = osc_share_snapshots.CreateShareSnapshot(self.app, None)
@@ -158,6 +161,63 @@ class TestShareSnapshotCreate(TestShareSnapshot):
self.assertCountEqual(self.columns, columns) self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data) self.assertCountEqual(self.data, data)
def test_share_snapshot_create_wait(self):
arglist = [
self.share.id,
'--wait'
]
verifylist = [
('share', self.share.id),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.snapshots_mock.create.assert_called_with(
share=self.share,
force=False,
name=None,
description=None
)
self.snapshots_mock.get.assert_called_with(
self.share_snapshot.id)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
@mock.patch('manilaclient.osc.v2.share_snapshots.LOG')
def test_share_snapshot_create_wait_error(self, mock_logger):
arglist = [
self.share.id,
'--wait'
]
verifylist = [
('share', self.share.id),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_status', return_value=False):
columns, data = self.cmd.take_action(parsed_args)
self.snapshots_mock.create.assert_called_with(
share=self.share,
force=False,
name=None,
description=None
)
mock_logger.error.assert_called_with(
"ERROR: Share snapshot is in error state.")
self.snapshots_mock.get.assert_called_with(
self.share_snapshot.id)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
class TestShareSnapshotDelete(TestShareSnapshot): class TestShareSnapshotDelete(TestShareSnapshot):
@@ -245,6 +305,42 @@ class TestShareSnapshotDelete(TestShareSnapshot):
self.cmd.take_action, self.cmd.take_action,
parsed_args) parsed_args)
def test_share_snapshot_delete_wait(self):
arglist = [
self.share_snapshot.id,
'--wait'
]
verifylist = [
('snapshot', [self.share_snapshot.id]),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=True):
result = self.cmd.take_action(parsed_args)
self.snapshots_mock.delete.assert_called_with(self.share_snapshot)
self.assertIsNone(result)
def test_share_snapshot_delete_wait_error(self):
arglist = [
self.share_snapshot.id,
'--wait'
]
verifylist = [
('snapshot', [self.share_snapshot.id]),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=False):
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args
)
class TestShareSnapshotShow(TestShareSnapshot): class TestShareSnapshotShow(TestShareSnapshot):
@@ -645,8 +741,13 @@ class TestShareSnapshotAdopt(TestShareSnapshot):
self.shares_mock.get.return_value = self.share self.shares_mock.get.return_value = self.share
self.share_snapshot = ( self.share_snapshot = (
manila_fakes.FakeShareSnapshot.create_one_snapshot()) manila_fakes.FakeShareSnapshot.create_one_snapshot(
attrs={
'status': 'available'
}
))
self.snapshots_mock.get.return_value = self.share_snapshot
self.export_location = ( self.export_location = (
manila_fakes.FakeShareExportLocation.create_one_export_location()) manila_fakes.FakeShareExportLocation.create_one_export_location())
@@ -748,6 +849,60 @@ class TestShareSnapshotAdopt(TestShareSnapshot):
self.assertCountEqual(self.columns, columns) self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data) self.assertCountEqual(self.data, data)
def test_snapshot_adopt_wait(self):
arglist = [
self.share.id,
self.export_location.fake_path,
'--wait'
]
verifylist = [
('share', self.share.id),
('provider_location', self.export_location.fake_path),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.snapshots_mock.get.assert_called_with(self.share_snapshot.id)
self.snapshots_mock.manage.assert_called_with(
share=self.share,
provider_location=self.export_location.fake_path,
driver_options={},
name=None,
description=None
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_snapshot_adopt_wait_error(self):
arglist = [
self.share.id,
self.export_location.fake_path,
'--wait'
]
verifylist = [
('share', self.share.id),
('provider_location', self.export_location.fake_path),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_status', return_value=False):
columns, data = self.cmd.take_action(parsed_args)
self.snapshots_mock.get.assert_called_with(self.share_snapshot.id)
self.snapshots_mock.manage.assert_called_with(
share=self.share,
provider_location=self.export_location.fake_path,
driver_options={},
name=None,
description=None
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
class TestShareSnapshotAbandon(TestShareSnapshot): class TestShareSnapshotAbandon(TestShareSnapshot):
@@ -755,7 +910,9 @@ class TestShareSnapshotAbandon(TestShareSnapshot):
super(TestShareSnapshotAbandon, self).setUp() super(TestShareSnapshotAbandon, self).setUp()
self.share_snapshot = ( self.share_snapshot = (
manila_fakes.FakeShareSnapshot.create_one_snapshot()) manila_fakes.FakeShareSnapshot.create_one_snapshot(
attrs={'status': 'available'}
))
self.snapshots_mock.get.return_value = self.share_snapshot self.snapshots_mock.get.return_value = self.share_snapshot
@@ -802,6 +959,42 @@ class TestShareSnapshotAbandon(TestShareSnapshot):
len(share_snapshots)) len(share_snapshots))
self.assertIsNone(result) self.assertIsNone(result)
def test_share_snapshot_abandon_wait(self):
arglist = [
self.share_snapshot.id,
'--wait'
]
verifylist = [
('snapshot', [self.share_snapshot.id]),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=True):
result = self.cmd.take_action(parsed_args)
self.snapshots_mock.unmanage.assert_called_with(
self.share_snapshot)
self.assertIsNone(result)
def test_share_snapshot_abandon_wait_error(self):
arglist = [
self.share_snapshot.id,
'--wait'
]
verifylist = [
('snapshot', [self.share_snapshot.id]),
('wait', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('osc_lib.utils.wait_for_delete', return_value=False):
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
class TestShareSnapshotAccessAllow(TestShareSnapshot): class TestShareSnapshotAccessAllow(TestShareSnapshot):