summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/locale/pt_BR/LC_MESSAGES/doc.po74
-rw-r--r--openstack_auth/locale/pt_BR/LC_MESSAGES/django.po43
-rw-r--r--openstack_dashboard/dashboards/admin/instances/views.py28
-rw-r--r--openstack_dashboard/dashboards/project/instances/tables.py10
-rw-r--r--openstack_dashboard/dashboards/project/instances/tests.py53
-rw-r--r--openstack_dashboard/dashboards/project/instances/utils.py43
-rw-r--r--openstack_dashboard/dashboards/project/instances/views.py17
-rw-r--r--openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py5
-rw-r--r--releasenotes/notes/bug_1963652_fix_policy_for_resume-a719efb23054c708.yaml6
9 files changed, 243 insertions, 36 deletions
diff --git a/doc/source/locale/pt_BR/LC_MESSAGES/doc.po b/doc/source/locale/pt_BR/LC_MESSAGES/doc.po
index d76da1a50..ad80870f2 100644
--- a/doc/source/locale/pt_BR/LC_MESSAGES/doc.po
+++ b/doc/source/locale/pt_BR/LC_MESSAGES/doc.po
@@ -1,14 +1,15 @@
# Rodrigo Loures <rmoraesloures@gmail.com>, 2018. #zanata
+# Yago Lourenço <yagoasl@labnet.nce.ufrj.br>, 2022. #zanata
msgid ""
msgstr ""
-"Project-Id-Version: horizon 16.0.0.0b2.dev26\n"
+"Project-Id-Version: horizon 18.6.4.dev3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-06-24 03:59-0500\n"
+"POT-Creation-Date: 2022-04-04 10:12+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2018-10-19 10:05+0000\n"
-"Last-Translator: Rodrigo Loures <rmoraesloures@gmail.com>\n"
+"PO-Revision-Date: 2022-04-11 11:50+0000\n"
+"Last-Translator: Yago Lourenço <yagoasl@labnet.nce.ufrj.br>\n"
"Language-Team: Portuguese (Brazil)\n"
"Language: pt_BR\n"
"X-Generator: Zanata 4.3.3\n"
@@ -20,15 +21,60 @@ msgstr ":ref:`genindex`"
msgid ":ref:`modindex`"
msgstr ":ref:`modindex`"
+msgid ""
+"A Python class representing a sub-navigation item (e.g. \"instances\") which "
+"contains all the necessary logic (views, forms, tests, etc.) for that "
+"interface."
+msgstr ""
+"Uma classe Python que representa um item de sub-navegação (por exemplo, "
+"\"instâncias\") que contém toda a lógica necessária (visualizações, "
+"formulários, testes, etc.) para essa interface."
+
+msgid ""
+"A Python class representing a top-level navigation item (e.g. \"project\") "
+"which provides a consistent API for Horizon-compatible applications."
+msgstr ""
+"Uma classe Python que representa um item de navegação de nível superior (por "
+"exemplo, \"projeto\") que fornece uma API consistente para aplicativos "
+"compatíveis com o Horizon."
+
+msgid "Contributor Docs"
+msgstr "Documentos do Colaborador"
+
msgid "Dashboard"
msgstr "Dashboard"
+msgid ""
+"For a more in-depth look at Horizon and its architecture, see the :ref:"
+"`contributor-intro`."
+msgstr ""
+"Para uma visão mais detalhada do Horizon e sua arquitetura, veja a :ref:"
+"`contributor-intro`."
+
+msgid ""
+"For those wishing to develop Horizon itself, or go in-depth with building "
+"your own :class:`~horizon.Dashboard` or :class:`~horizon.Panel` classes, the "
+"following documentation is provided."
+msgstr ""
+"Para aqueles que desejam desenvolver o próprio Horizon, ou aprofundar a "
+"construção de suas próprias classes :class:`~horizon.Dashboard` ou :class:"
+"`~horizon.Panel`, a seguinte documentação é fornecida."
+
msgid "Glossary"
msgstr "Glossário"
msgid "Horizon"
msgstr "Horizon"
+msgid ""
+"Horizon is the canonical implementation of `OpenStack's Dashboard <https://"
+"github.com/openstack/horizon>`_, which provides a web based user interface "
+"to OpenStack services including Nova, Swift, Keystone, etc."
+msgstr ""
+"Horizon é a implementação canônica do `OpenStack's Dashboard <https://github."
+"com/openstack/horizon>`_, que fornece uma interface de usuário baseada na "
+"web para serviços OpenStack, incluindo Nova, Swift, Keystone, etc."
+
msgid "Horizon: The OpenStack Dashboard Project"
msgstr "Horizon: o projeto de Dashboard do Openstack"
@@ -50,10 +96,30 @@ msgstr "Projeto"
msgid "Release Notes"
msgstr "Notas de versão"
+msgid "See https://docs.openstack.org/releasenotes/horizon/."
+msgstr "Veja https://docs.openstack.org/releasenotes/horizon/."
+
+msgid ""
+"The OpenStack dashboard project. Also the name of the top-level Python "
+"object which handles registration for the app."
+msgstr ""
+"O painel de projeto OpenStack. Também o nome do objeto Python de nível "
+"superior que trata do registro do aplicativo."
+
msgid "To learn what you need to know to get going, see the :ref:`quickstart`."
msgstr ""
"Para aprender o que você precisa saber para iniciar, veja o :ref:"
"`quickstart`."
+msgid ""
+"Used in user-facing text in place of the term \"Tenant\" which is Keystone's "
+"word."
+msgstr ""
+"Usado em texto voltado para o usuário no lugar do termo \"Tenant\", que é a "
+"palavra da Keystone."
+
+msgid "User Documentation"
+msgstr "Documentação do usuário"
+
msgid "Using Horizon"
msgstr "Usando o Horizon"
diff --git a/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po b/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po
index 36814acdf..3d8e00f7c 100644
--- a/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po
+++ b/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po
@@ -1,15 +1,16 @@
# Fernando Pimenta <fernando.c.pimenta@gmail.com>, 2018. #zanata
# Marcelo Dieder <marcelodieder@gmail.com>, 2018. #zanata
+# Yago Lourenço <yagoasl@labnet.nce.ufrj.br>, 2022. #zanata
msgid ""
msgstr ""
"Project-Id-Version: horizon VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2019-09-13 12:32+0000\n"
+"POT-Creation-Date: 2022-04-04 10:12+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2018-10-03 07:54+0000\n"
-"Last-Translator: Fernando Pimenta <fernando.c.pimenta@gmail.com>\n"
+"PO-Revision-Date: 2022-04-11 11:39+0000\n"
+"Last-Translator: Yago Lourenço <yagoasl@labnet.nce.ufrj.br>\n"
"Language-Team: Portuguese (Brazil)\n"
"Language: pt_BR\n"
"X-Generator: Zanata 4.3.3\n"
@@ -22,6 +23,14 @@ msgstr ""
msgid "Authenticate using"
msgstr "Autenticar utilizando"
+msgid "Confirm password"
+msgstr "Confirmar senha"
+
+msgid "Cookies may be turned off. Make sure cookies are enabled and try again."
+msgstr ""
+"Os cookies podem ser desativados. Certifique-se de que os cookies estão "
+"ativados e tente novamente."
+
msgid "Could not find service provider ID on keystone."
msgstr "Não foi possível localizar o ID do provedor do serviço no keystone."
@@ -40,6 +49,9 @@ msgstr "Credenciais inválidas"
msgid "K2K Federation not setup for this session"
msgstr "Federação K2K não configurada para esta sessão"
+msgid "New password"
+msgstr "Nova Senha"
+
msgid ""
"No authentication backend could be determined to handle the provided "
"credentials."
@@ -47,9 +59,24 @@ msgstr ""
"Nenhum backend de autenticação pode ser determinado para lidar com as "
"credenciais fornecidas."
+msgid "Old password and new password must be different."
+msgstr "A senha antiga e a nova senha devem ser diferentes."
+
+msgid "Original password"
+msgstr "Senha Original"
+
msgid "Password"
msgstr "Senha"
+msgid "Password changed. Please log in to continue."
+msgstr "Senha alterada. Por favor faça o login para continuar."
+
+msgid "Password expired."
+msgstr "Senha expirada."
+
+msgid "Passwords do not match."
+msgstr "As senhas não coincidem."
+
#, python-format
msgid "Please consider changing your password, it will expire in %s minutes"
msgstr "Por favor, considere alterar sua senha, ela irá expirar em %s minutos."
@@ -66,6 +93,10 @@ msgid "Service provider authentication failed. %s"
msgstr "Autenticação do provedor de serviços falhou. %s"
#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\" successful."
+msgstr "Mudar para o Provedor Keystone \"%(keystone_provider)s\" com sucesso."
+
+#, python-format
msgid "Switch to project \"%(project_name)s\" successful."
msgstr "Troca para o projeto \"%(project_name)s\" com sucesso."
@@ -81,8 +112,14 @@ msgstr "Não é possível recuperar domínios autorizados."
msgid "Unable to retrieve authorized projects."
msgstr "Não é possível recuperar projetos autorizados."
+msgid "Unable to update the user password."
+msgstr "Não foi possível atualizar a senha do usuário."
+
msgid "User Name"
msgstr "Nome de Usuário"
msgid "You are not authorized for any projects or domains."
msgstr "Você não está autorizado para nenhum projeto ou domínio."
+
+msgid "Your password has expired. Please set a new password."
+msgstr "Sua senha expirou. Por favor, defina uma nova senha."
diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py
index 8ca198772..d8a6e2cb8 100644
--- a/openstack_dashboard/dashboards/admin/instances/views.py
+++ b/openstack_dashboard/dashboards/admin/instances/views.py
@@ -108,6 +108,12 @@ class AdminIndexView(tables.PagedTableMixin, tables.DataTableView):
exceptions.handle(self.request, ignore=True)
return {}
+ def _get_images_by_name(self, image_name):
+ result = api.glance.image_list_detailed(
+ self.request, filters={'name': image_name})
+ images = result[0]
+ return dict((image.id, image) for image in images)
+
def _get_flavors(self):
# Gather our flavors to correlate against IDs
try:
@@ -151,22 +157,32 @@ class AdminIndexView(tables.PagedTableMixin, tables.DataTableView):
self._needs_filter_first = False
- instances = self._get_instances(search_opts, sort_dir)
results = futurist_utils.call_functions_parallel(
- (self._get_images, [tuple(instances)]),
self._get_flavors,
self._get_tenants)
- image_dict, flavor_dict, tenant_dict = results
+ flavor_dict, tenant_dict = results
- non_api_filter_info = (
+ non_api_filter_info = [
('project', 'tenant_id', tenant_dict.values()),
- ('image_name', 'image', image_dict.values()),
('flavor_name', 'flavor', flavor_dict.values()),
- )
+ ]
+
+ filter_by_image_name = 'image_name' in search_opts
+ if filter_by_image_name:
+ image_dict = self._get_images_by_name(search_opts['image_name'])
+ non_api_filter_info.append(
+ ('image_name', 'image', image_dict.values())
+ )
+
if not views.process_non_api_filters(search_opts, non_api_filter_info):
self._more = False
return []
+ instances = self._get_instances(search_opts, sort_dir)
+
+ if not filter_by_image_name:
+ image_dict = self._get_images(tuple(instances))
+
# Loop through instances to get image, flavor and tenant info.
for inst in instances:
if hasattr(inst, 'image') and isinstance(inst.image, dict):
diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py
index 56af9b8f3..5c4b18db1 100644
--- a/openstack_dashboard/dashboards/project/instances/tables.py
+++ b/openstack_dashboard/dashboards/project/instances/tables.py
@@ -39,6 +39,8 @@ from horizon.utils import filters
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.floating_ips import workflows
from openstack_dashboard.dashboards.project.instances import tabs
+from openstack_dashboard.dashboards.project.instances \
+ import utils as instance_utils
from openstack_dashboard.dashboards.project.instances.workflows \
import resize_instance
from openstack_dashboard.dashboards.project.instances.workflows \
@@ -332,7 +334,7 @@ class ToggleSuspend(tables.BatchAction):
if self.suspended:
self.current_present_action = RESUME
policy_rules = (
- ("compute", "os_compute_api:os-rescue"),)
+ ("compute", "os_compute_api:os-suspend-server:resume"),)
else:
self.current_present_action = SUSPEND
policy_rules = (
@@ -799,8 +801,8 @@ class UpdateRow(tables.Row):
def get_data(self, request, instance_id):
instance = api.nova.server_get(request, instance_id)
try:
- instance.full_flavor = api.nova.flavor_get(request,
- instance.flavor["id"])
+ instance.full_flavor = instance_utils.resolve_flavor(request,
+ instance)
except Exception:
exceptions.handle(request,
_('Unable to retrieve flavor information '
@@ -1055,7 +1057,7 @@ def get_flavor(instance):
"size_disk": size_disk,
"size_ram": size_ram,
"vcpus": instance.full_flavor.vcpus,
- "flavor_id": instance.full_flavor.id
+ "flavor_id": getattr(instance.full_flavor, 'id', None)
}
return template.loader.render_to_string(template_name, context)
return _("Not available")
diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py
index b7ef8cac8..722ca8668 100644
--- a/openstack_dashboard/dashboards/project/instances/tests.py
+++ b/openstack_dashboard/dashboards/project/instances/tests.py
@@ -4602,12 +4602,26 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
def test_disassociate_floating_ip_with_release(self):
self._test_disassociate_floating_ip(is_release=True)
+ def _populate_server_flavor_nova_api_ge_2_47(self, server):
+ flavor_id = server.flavor['id']
+ flavor = self.flavors.get(id=flavor_id)
+ server.flavor = {
+ 'original_name': flavor.name,
+ 'vcpus': flavor.vcpus,
+ 'ram': flavor.ram,
+ 'swap': flavor.swap,
+ 'disk': flavor.disk,
+ 'ephemeral': flavor.ephemeral,
+ 'extra_specs': flavor.extra_specs,
+ }
+ return server
+
@helpers.create_mocks({api.nova: ('server_get',
'flavor_list',
'tenant_absolute_limits',
'is_feature_available',
'extension_supported')})
- def test_instance_resize_get(self):
+ def _test_instance_resize_get(self, server, nova_api_lt_2_47=False):
server = self.servers.first()
self.mock_server_get.return_value = server
self.mock_flavor_list.return_value = self.flavors.list()
@@ -4618,14 +4632,35 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
url = reverse('horizon:project:instances:resize', args=[server.id])
res = self.client.get(url)
+ workflow = res.context['workflow']
self.assertTemplateUsed(res, views.WorkflowView.template_name)
+ self.assertEqual(res.context['workflow'].name,
+ workflows.ResizeInstance.name)
+ self.assertContains(res, 'Disk Partition')
config_drive_field_label = 'Configuration Drive'
self.assertNotContains(res, config_drive_field_label)
+ step = workflow.get_step("flavor_choice")
+ self.assertEqual(step.action.initial['old_flavor_name'],
+ self.flavors.first().name)
+
+ step = workflow.get_step("setadvancedaction")
+ self.assertEqual(step.action.fields['disk_config'].label,
+ 'Disk Partition')
+ self.assertQuerysetEqual(workflow.steps,
+ ['<SetFlavorChoice: flavor_choice>',
+ '<SetAdvanced: setadvancedaction>'])
option = '<option value="%s">%s</option>'
+
+ def is_original_flavor(server, flavor, nova_api_lt_2_47):
+ if nova_api_lt_2_47:
+ return flavor.id == server.flavor['id']
+ else:
+ return flavor.name == server.flavor['original_name']
+
for flavor in self.flavors.list():
- if flavor.id == server.flavor['id']:
+ if is_original_flavor(server, flavor, nova_api_lt_2_47):
self.assertNotContains(res, option % (flavor.id, flavor.name))
else:
self.assertContains(res, option % (flavor.id, flavor.name))
@@ -4640,6 +4675,15 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
self._check_extension_supported({'DiskConfig': 1,
'ServerGroups': 1})
+ def test_instance_resize_get_nova_api_lt_2_47(self):
+ server = self.servers.first()
+ self._test_instance_resize_get(server, nova_api_lt_2_47=True)
+
+ def test_instance_resize_get_nova_api_ge_2_47(self):
+ server = self.servers.first()
+ self._populate_server_flavor_nova_api_ge_2_47(server)
+ self._test_instance_resize_get(server)
+
@helpers.create_mocks({api.nova: ('server_get',)})
def test_instance_resize_get_server_get_exception(self):
server = self.servers.first()
@@ -4655,10 +4699,9 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
helpers.IsHttpRequest(), server.id)
@helpers.create_mocks({api.nova: ('server_get',
- 'flavor_list',)})
+ 'flavor_list')})
def test_instance_resize_get_flavor_list_exception(self):
server = self.servers.first()
-
self.mock_server_get.return_value = server
self.mock_flavor_list.side_effect = self.exceptions.nova
@@ -4672,6 +4715,8 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
server.id)
self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
+ # TODO(amotoki): This is requred only when nova API <=2.46 is used.
+ # Once server_get() uses nova API >=2.47 only, this test can be droppped.
@helpers.create_mocks({api.nova: ('server_get',
'flavor_list',
'flavor_get',
diff --git a/openstack_dashboard/dashboards/project/instances/utils.py b/openstack_dashboard/dashboards/project/instances/utils.py
index 11bd5dc68..0639690db 100644
--- a/openstack_dashboard/dashboards/project/instances/utils.py
+++ b/openstack_dashboard/dashboards/project/instances/utils.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from collections import namedtuple
import logging
from operator import itemgetter
@@ -232,3 +233,45 @@ def server_group_field_data(request):
return [("", _("Select Server Group")), ] + server_groups_list
return [("", _("No server groups available")), ]
+
+
+def resolve_flavor(request, instance, flavors=None, **kwargs):
+ """Resolves name of instance flavor independent of API microversion
+
+ :param request: django http request object
+ :param instance: api._nova.Server instance to resolve flavor
+ :param flavors: dict of flavors already retrieved
+ :param kwargs: flavor parameters to return if hit some flavor discrepancy
+ :return: flavor name or default placeholder
+ """
+ def flavor_from_dict(flavor_dict):
+ """Creates flavor-like objects from dictionary
+
+ :param flavor_dict: dictionary contains vcpu, ram, name, etc. values
+ :return: novaclient.v2.flavors.Flavor like object
+ """
+ return namedtuple('Flavor', flavor_dict.keys())(*flavor_dict.values())
+
+ if flavors is None:
+ flavors = {}
+ flavor_id = instance.flavor.get('id')
+ if flavor_id: # Nova API <=2.46
+ if flavor_id in flavors:
+ return flavors[flavor_id]
+ try:
+ return api.nova.flavor_get(request, flavor_id)
+ except Exception:
+ msg = _('Unable to retrieve flavor information '
+ 'for instance "%s".') % instance.id
+ exceptions.handle(request, msg, ignore=True)
+ fallback_flavor = {
+ 'vcpus': 0, 'ram': 0, 'disk': 0, 'ephemeral': 0, 'swap': 0,
+ 'name': _('Not available'),
+ 'original_name': _('Not available'),
+ 'extra_specs': {},
+ }
+ fallback_flavor.update(kwargs)
+ return flavor_from_dict(fallback_flavor)
+ else:
+ instance.flavor['name'] = instance.flavor['original_name']
+ return flavor_from_dict(instance.flavor)
diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py
index 6e7a76295..cdc4d59b3 100644
--- a/openstack_dashboard/dashboards/project/instances/views.py
+++ b/openstack_dashboard/dashboards/project/instances/views.py
@@ -51,6 +51,8 @@ from openstack_dashboard.dashboards.project.instances \
from openstack_dashboard.dashboards.project.instances \
import tabs as project_tabs
from openstack_dashboard.dashboards.project.instances \
+ import utils as instance_utils
+from openstack_dashboard.dashboards.project.instances \
import workflows as project_workflows
from openstack_dashboard.dashboards.project.networks.ports \
import views as port_views
@@ -599,19 +601,9 @@ class ResizeView(workflows.WorkflowView):
redirect = reverse("horizon:project:instances:index")
msg = _('Unable to retrieve instance details.')
exceptions.handle(self.request, msg, redirect=redirect)
- flavor_id = instance.flavor['id']
flavors = self.get_flavors()
- if flavor_id in flavors:
- instance.flavor_name = flavors[flavor_id].name
- else:
- try:
- flavor = api.nova.flavor_get(self.request, flavor_id)
- instance.flavor_name = flavor.name
- except Exception:
- msg = _('Unable to retrieve flavor information for instance '
- '"%s".') % instance_id
- exceptions.handle(self.request, msg, ignore=True)
- instance.flavor_name = _("Not available")
+ flavor = instance_utils.resolve_flavor(self.request, instance, flavors)
+ instance.flavor_name = flavor.name
return instance
@memoized.memoized_method
@@ -632,7 +624,6 @@ class ResizeView(workflows.WorkflowView):
initial.update(
{'instance_id': self.kwargs['instance_id'],
'name': getattr(_object, 'name', None),
- 'old_flavor_id': _object.flavor['id'],
'old_flavor_name': getattr(_object, 'flavor_name', ''),
'flavors': self.get_flavors()})
return initial
diff --git a/openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py b/openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py
index 1fb4869a5..8634842f0 100644
--- a/openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py
+++ b/openstack_dashboard/dashboards/project/instances/workflows/resize_instance.py
@@ -47,11 +47,12 @@ class SetFlavorChoiceAction(workflows.Action):
"_flavors_and_quotas.html")
def populate_flavor_choices(self, request, context):
- old_flavor_id = context.get('old_flavor_id')
+ old_flavor_name = context.get('old_flavor_name')
flavors = context.get('flavors').values()
# Remove current flavor from the list of flavor choices
- flavors = [flavor for flavor in flavors if flavor.id != old_flavor_id]
+ flavors = [flavor for flavor in flavors
+ if flavor.name != old_flavor_name]
if flavors:
if len(flavors) > 1:
diff --git a/releasenotes/notes/bug_1963652_fix_policy_for_resume-a719efb23054c708.yaml b/releasenotes/notes/bug_1963652_fix_policy_for_resume-a719efb23054c708.yaml
new file mode 100644
index 000000000..6c2b31faf
--- /dev/null
+++ b/releasenotes/notes/bug_1963652_fix_policy_for_resume-a719efb23054c708.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ Previously, ToggleSuspend class checked os-rescue policy for resume operation.
+ By this fix, the class checks 'os_compute_api:os-suspend-server:resume' policy
+ to align to resume operation.