lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 1 | # Copyright 2021 Red Hat, Inc. |
| 2 | # All Rights Reserved. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 5 | # not use this file except in compliance with the License. You may obtain |
| 6 | # a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 13 | # License for the specific language governing permissions and limitations |
| 14 | # under the License. |
| 15 | |
| 16 | import time |
| 17 | |
| 18 | import six |
| 19 | from tempest import config |
| 20 | from tempest.lib import exceptions |
| 21 | |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 22 | from manila_tempest_tests.services.share.v2.json import shares_client |
| 23 | from manila_tempest_tests import share_exceptions |
| 24 | |
| 25 | CONF = config.CONF |
| 26 | LATEST_MICROVERSION = CONF.share.max_api_microversion |
| 27 | |
| 28 | |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 29 | def _get_access_rule(body, rule_id): |
| 30 | for rule in body: |
| 31 | if rule['id'] in rule_id: |
| 32 | return rule |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 33 | |
| 34 | |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 35 | def _get_name_of_raise_method(resource_name): |
| 36 | if resource_name == 'snapshot_access_rule': |
| 37 | return 'AccessRuleBuildErrorException' |
| 38 | if resource_name == 'share_replica': |
| 39 | return 'ShareInstanceBuildErrorException' |
| 40 | resource_name = resource_name.title() |
| 41 | name = resource_name.replace('_', '') |
| 42 | return name + 'BuildErrorException' |
| 43 | |
| 44 | |
| 45 | def wait_for_resource_status(client, resource_id, status, |
| 46 | resource_name='share', rule_id=None, |
| 47 | status_attr='status', |
| 48 | raise_rule_in_error_state=True, |
| 49 | version=LATEST_MICROVERSION): |
| 50 | """Waits for a resource to reach a given status.""" |
| 51 | |
| 52 | get_resource_action = { |
| 53 | 'share': 'get_share', |
| 54 | 'snapshot': 'get_snapshot', |
| 55 | 'share_server': 'show_share_server', |
| 56 | 'share_instance': 'get_share_instance', |
| 57 | 'snapshot_instance': 'get_snapshot_instance', |
| 58 | 'access_rule': 'list_access_rules', |
| 59 | 'snapshot_access_rule': 'get_snapshot_access_rule', |
| 60 | 'share_group': 'get_share_group', |
| 61 | 'share_group_snapshot': 'get_share_group_snapshot', |
| 62 | 'share_replica': 'get_share_replica', |
| 63 | } |
| 64 | |
| 65 | # Since API v2 requests require an additional parameter for micro-versions, |
| 66 | # it's necessary to pass the required parameters according to the version. |
| 67 | resource_action = getattr(client, get_resource_action[resource_name]) |
| 68 | method_args = [resource_id] |
| 69 | method_kwargs = {} |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 70 | if isinstance(client, shares_client.SharesV2Client): |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 71 | method_kwargs.update({'version': version}) |
| 72 | if resource_name == 'snapshot_access_rule': |
| 73 | method_args.insert(1, rule_id) |
| 74 | body = resource_action(*method_args, **method_kwargs) |
| 75 | |
| 76 | if resource_name == 'access_rule': |
| 77 | status_attr = 'state' |
| 78 | body = _get_access_rule(body, rule_id) |
| 79 | |
| 80 | resource_status = body[status_attr] |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 81 | start = int(time.time()) |
| 82 | |
| 83 | exp_status = status if isinstance(status, list) else [status] |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 84 | while resource_status not in exp_status: |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 85 | time.sleep(client.build_interval) |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 86 | body = resource_action(*method_args, **method_kwargs) |
| 87 | |
| 88 | if resource_name == 'access_rule': |
| 89 | status_attr = 'state' |
| 90 | body = _get_access_rule(body, rule_id) |
| 91 | |
| 92 | resource_status = body[status_attr] |
| 93 | |
| 94 | if resource_status in exp_status: |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 95 | return |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 96 | elif 'error' in resource_status.lower() and raise_rule_in_error_state: |
| 97 | raise_method = _get_name_of_raise_method(resource_name) |
| 98 | resource_exception = getattr(share_exceptions, raise_method) |
| 99 | raise resource_exception(resource_id=resource_id) |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 100 | if int(time.time()) - start >= client.build_timeout: |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 101 | message = ('%s %s failed to reach %s status (current %s) ' |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 102 | 'within the required time (%s s).' % |
lkuchlan | f7fc5b6 | 2021-01-26 14:53:43 +0200 | [diff] [blame] | 103 | (resource_name.replace('_', ' '), resource_id, status, |
| 104 | resource_status, client.build_timeout)) |
lkuchlan | 540e74a | 2021-01-19 18:08:25 +0200 | [diff] [blame] | 105 | raise exceptions.TimeoutException(message) |
| 106 | |
| 107 | |
| 108 | def wait_for_migration_status(client, share_id, dest_host, status_to_wait, |
| 109 | version=LATEST_MICROVERSION): |
| 110 | """Waits for a share to migrate to a certain host.""" |
| 111 | statuses = ((status_to_wait,) |
| 112 | if not isinstance(status_to_wait, (tuple, list, set)) |
| 113 | else status_to_wait) |
| 114 | share = client.get_share(share_id, version=version) |
| 115 | migration_timeout = CONF.share.migration_timeout |
| 116 | start = int(time.time()) |
| 117 | while share['task_state'] not in statuses: |
| 118 | time.sleep(client.build_interval) |
| 119 | share = client.get_share(share_id, version=version) |
| 120 | if share['task_state'] in statuses: |
| 121 | break |
| 122 | elif share['task_state'] == 'migration_error': |
| 123 | raise share_exceptions.ShareMigrationException( |
| 124 | share_id=share['id'], src=share['host'], dest=dest_host) |
| 125 | elif int(time.time()) - start >= migration_timeout: |
| 126 | message = ('Share %(share_id)s failed to reach a status in' |
| 127 | '%(status)s when migrating from host %(src)s to ' |
| 128 | 'host %(dest)s within the required time ' |
| 129 | '%(timeout)s.' % { |
| 130 | 'src': share['host'], |
| 131 | 'dest': dest_host, |
| 132 | 'share_id': share['id'], |
| 133 | 'timeout': client.build_timeout, |
| 134 | 'status': six.text_type(statuses), |
| 135 | }) |
| 136 | raise exceptions.TimeoutException(message) |
| 137 | return share |
| 138 | |
| 139 | |
| 140 | def wait_for_snapshot_access_rule_deletion(client, snapshot_id, rule_id): |
| 141 | rule = client.get_snapshot_access_rule(snapshot_id, rule_id) |
| 142 | start = int(time.time()) |
| 143 | |
| 144 | while rule is not None: |
| 145 | time.sleep(client.build_interval) |
| 146 | |
| 147 | rule = client.get_snapshot_access_rule(snapshot_id, rule_id) |
| 148 | |
| 149 | if rule is None: |
| 150 | return |
| 151 | if int(time.time()) - start >= client.build_timeout: |
| 152 | message = ('The snapshot access rule %(id)s failed to delete ' |
| 153 | 'within the required time (%(time)ss).' % |
| 154 | { |
| 155 | 'time': client.build_timeout, |
| 156 | 'id': rule_id, |
| 157 | }) |
| 158 | raise exceptions.TimeoutException(message) |
| 159 | |
| 160 | |
| 161 | def wait_for_message(client, resource_id): |
| 162 | """Waits until a message for a resource with given id exists""" |
| 163 | start = int(time.time()) |
| 164 | message = None |
| 165 | |
| 166 | while not message: |
| 167 | time.sleep(client.build_interval) |
| 168 | for msg in client.list_messages(): |
| 169 | if msg['resource_id'] == resource_id: |
| 170 | return msg |
| 171 | |
| 172 | if int(time.time()) - start >= client.build_timeout: |
| 173 | message = ('No message for resource with id %s was created in' |
| 174 | ' the required time (%s s).' % |
| 175 | (resource_id, client.build_timeout)) |
| 176 | raise exceptions.TimeoutException(message) |