diff options
31 files changed, 160 insertions, 138 deletions
diff --git a/.zuul.d/base.yaml b/.zuul.d/base.yaml index f6aa71360..06f8fd3a1 100644 --- a/.zuul.d/base.yaml +++ b/.zuul.d/base.yaml @@ -10,6 +10,7 @@ - job: name: horizon-selenium-headless parent: horizon-openstack-tox-base + nodeset: ubuntu-focal pre-run: playbooks/horizon-selenium-headless/pre.yaml vars: tox_envlist: selenium-headless diff --git a/.zuul.d/tempest-and-integrated.yaml b/.zuul.d/tempest-and-integrated.yaml index df2e9b52a..c33578af0 100644 --- a/.zuul.d/tempest-and-integrated.yaml +++ b/.zuul.d/tempest-and-integrated.yaml @@ -1,6 +1,7 @@ - job: name: horizon-integration-tests parent: devstack + nodeset: openstack-single-node-focal pre-run: playbooks/horizon-devstack-integration/pre.yaml run: playbooks/horizon-devstack-integration/run.yaml post-run: playbooks/horizon-devstack-integration/post.yaml diff --git a/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js index 27ab57d29..c4f8fb5af 100644 --- a/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js +++ b/horizon/static/framework/widgets/metadata/tree/metadata-tree-item.controller.js @@ -16,6 +16,8 @@ (function () { 'use strict'; + var READONLY_PROPERTIES = ['os_hash_algo', 'os_hash_value']; + angular .module('horizon.framework.widgets.metadata.tree') .controller('MetadataTreeItemController', MetadataTreeItemController); @@ -33,6 +35,12 @@ ctrl.opened = false; this.$onInit = function init() { + if ('item' in ctrl && 'leaf' in ctrl.item && + READONLY_PROPERTIES.includes(ctrl.item.leaf.name)) { + ctrl.item.leaf.readonly = true; + ctrl.item.leaf.required = false; + } + if ('item' in ctrl && 'leaf' in ctrl.item && ctrl.item.leaf.type === 'array') { ctrl.values = ctrl.item.leaf.items.enum.filter(filter).sort(); diff --git a/horizon/static/framework/widgets/metadata/tree/tree.service.js b/horizon/static/framework/widgets/metadata/tree/tree.service.js index 1256985f5..47ba1a844 100644 --- a/horizon/static/framework/widgets/metadata/tree/tree.service.js +++ b/horizon/static/framework/widgets/metadata/tree/tree.service.js @@ -71,6 +71,8 @@ Property.prototype.setValue = function (value) { if (value === null) { this.value = this.type !== 'array' ? null : []; + // if the existing property is null, make the field not required + this.required = false; return; } diff --git a/openstack_dashboard/api/microversions.py b/openstack_dashboard/api/microversions.py index 9d33952ec..d31712ce8 100644 --- a/openstack_dashboard/api/microversions.py +++ b/openstack_dashboard/api/microversions.py @@ -37,6 +37,7 @@ MICROVERSION_FEATURES = { "auto_allocated_network": ["2.37", "2.60"], "key_types": ["2.2", "2.9"], "key_type_list": ["2.9"], + "rescue_instance_volume_based": ["2.87", "2.93"], }, "cinder": { "groups": ["3.27", "3.43", "3.48", "3.58"], diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index 981b1148d..03bdee1a9 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -665,9 +665,12 @@ def server_metadata_delete(request, instance_id, keys): @profiler.trace def server_rescue(request, instance_id, password=None, image=None): - _nova.novaclient(request).servers.rescue(instance_id, - password=password, - image=image) + microversion = get_microversion(request, "rescue_instance_volume_based") + _nova.novaclient(request, version=microversion).servers.rescue( + instance_id, + password=password, + image=image + ) @profiler.trace diff --git a/openstack_dashboard/dashboards/admin/flavors/workflows.py b/openstack_dashboard/dashboards/admin/flavors/workflows.py index 074924eb8..3244ad992 100644 --- a/openstack_dashboard/dashboards/admin/flavors/workflows.py +++ b/openstack_dashboard/dashboards/admin/flavors/workflows.py @@ -30,7 +30,7 @@ class CreateFlavorInfoAction(workflows.Action): _flavor_id_regex = (r'^[a-zA-Z0-9. _-]+$') _flavor_id_help_text = _("flavor id can only contain alphanumeric " "characters, underscores, periods, hyphens, " - "spaces.") + "spaces. Use 'auto' to automatically generate id") name = forms.CharField( label=_("Name"), max_length=255) @@ -93,7 +93,7 @@ class CreateFlavorInfoAction(workflows.Action): error_msg = _('The name "%s" is already used by ' 'another flavor.') % name self._errors['name'] = self.error_class([error_msg]) - if flavor.id == flavor_id: + if (flavor.id != 'auto') and (flavor.id == flavor_id): error_msg = _('The ID "%s" is already used by ' 'another flavor.') % flavor_id self._errors['flavor_id'] = self.error_class([error_msg]) diff --git a/openstack_dashboard/dashboards/project/floating_ips/tests.py b/openstack_dashboard/dashboards/project/floating_ips/tests.py index eca92dcd8..8c94c1f1f 100644 --- a/openstack_dashboard/dashboards/project/floating_ips/tests.py +++ b/openstack_dashboard/dashboards/project/floating_ips/tests.py @@ -90,7 +90,7 @@ class FloatingIpViewTests(test.TestCase): for p in self._get_compute_ports(): for ip in p.fixed_ips: targets.append(api.neutron.FloatingIpTarget( - p, ip['ip_address'], server_dict[p.device_id])) + p, ip['ip_address'], server_dict.get(p.device_id))) return targets @staticmethod diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 93151a410..70d32bc4b 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -3054,11 +3054,14 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): 'port_list_with_trunk_types')}) def test_interface_attach_get(self): server = self.servers.first() - self.mock_network_list_for_tenant.side_effect = [ - self.networks.list()[:1], - [], - ] - self.mock_port_list_with_trunk_types.return_value = self.ports.list() + tenant_networks = [net for net in self.networks.list() + if not net['router:external']] + net1 = tenant_networks[0] + self.mock_network_list_for_tenant.return_value = tenant_networks + ports = self.ports.list() + # Pick up the first unbound port for check + unbound_port = [p for p in ports if not p.device_owner][0] + self.mock_port_list_with_trunk_types.return_value = ports url = reverse('horizon:project:instances:attach_interface', args=[server.id]) @@ -3066,6 +3069,13 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): self.assertTemplateUsed(res, 'project/instances/attach_interface.html') + expected_label = ( + '%(port_name)s (%(ip_address)s) - %(net_name)s' + % {'port_name': unbound_port.name_or_id, + 'ip_address': unbound_port.fixed_ips[0]['ip_address'], + 'net_name': net1.name_or_id} + ) + self.assertContains(res, expected_label) self.mock_network_list_for_tenant.assert_has_calls([ mock.call(helpers.IsHttpRequest(), self.tenant.id), mock.call(helpers.IsHttpRequest(), self.tenant.id), @@ -3077,21 +3087,31 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): @helpers.create_mocks({api.neutron: ('network_list_for_tenant', 'port_list_with_trunk_types'), api.nova: ('interface_attach',)}) - def test_interface_attach_post(self): + def _test_interface_attach_post(self, by_port=False): fixed_ip = '10.0.0.10' server = self.servers.first() network = self.networks.first() - self.mock_network_list_for_tenant.side_effect = [ - [network], - [], - ] - self.mock_port_list_with_trunk_types.return_value = self.ports.list() + ports = self.ports.list() + # Pick up the first unbound port for check + unbound_port = [p for p in ports if not p.device_owner][0] + + self.mock_network_list_for_tenant.return_value = [network] + self.mock_port_list_with_trunk_types.return_value = ports self.mock_interface_attach.return_value = None - form_data = {'instance_id': server.id, - 'network': network.id, - 'specification_method': 'network', - 'fixed_ip': fixed_ip} + if by_port: + form_data = { + 'instance_id': server.id, + 'specification_method': 'port', + 'port': unbound_port.id, + } + else: + form_data = { + 'instance_id': server.id, + 'specification_method': 'network', + 'network': network.id, + 'fixed_ip': fixed_ip, + } url = reverse('horizon:project:instances:attach_interface', args=[server.id]) @@ -3107,9 +3127,20 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): self.assertEqual(2, self.mock_network_list_for_tenant.call_count) self.mock_port_list_with_trunk_types.assert_called_once_with( helpers.IsHttpRequest(), tenant_id=self.tenant.id) - self.mock_interface_attach.assert_called_once_with( - helpers.IsHttpRequest(), server.id, - net_id=network.id, fixed_ip=fixed_ip, port_id=None) + if by_port: + self.mock_interface_attach.assert_called_once_with( + helpers.IsHttpRequest(), server.id, + net_id=None, fixed_ip=None, port_id=unbound_port.id) + else: + self.mock_interface_attach.assert_called_once_with( + helpers.IsHttpRequest(), server.id, + net_id=network.id, fixed_ip=fixed_ip, port_id=None) + + def test_interface_attach_post_by_network(self): + self._test_interface_attach_post() + + def test_interface_attach_post_by_port(self): + self._test_interface_attach_post(by_port=True) @helpers.create_mocks({api.cinder: ('volume_list',)}) def test_volume_attach_get(self): diff --git a/openstack_dashboard/dashboards/project/snapshots/views.py b/openstack_dashboard/dashboards/project/snapshots/views.py index 7efc4a892..faf727926 100644 --- a/openstack_dashboard/dashboards/project/snapshots/views.py +++ b/openstack_dashboard/dashboards/project/snapshots/views.py @@ -12,7 +12,6 @@ from django.urls import reverse from django.urls import reverse_lazy -from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ from horizon import exceptions @@ -104,11 +103,8 @@ class UpdateView(forms.ModalFormView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['snapshot'] = self.get_object() - success_url = self.request.GET.get('success_url', "") args = (self.kwargs['snapshot_id'],) - params = urlencode({"success_url": success_url}) - context['submit_url'] = "?".join([reverse(self.submit_url, args=args), - params]) + context['submit_url'] = reverse(self.submit_url, args=args) return context def get_initial(self): @@ -117,12 +113,6 @@ class UpdateView(forms.ModalFormView): 'name': snapshot.name, 'description': snapshot.description} - def get_success_url(self): - success_url = self.request.GET.get( - "success_url", - reverse_lazy("horizon:project:snapshots:index")) - return success_url - class DetailView(tabs.TabView): tab_group_class = vol_snapshot_tabs.SnapshotDetailTabs diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js index 26086bc14..c38d75bc4 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js @@ -676,14 +676,17 @@ } function getImageType(image) { - if (image === null || !angular.isDefined(image.properties) || - !(angular.isDefined(image.properties.image_type) || - angular.isDefined(image.properties.block_device_mapping))) { + if (image === null || !image.properties) { return 'image'; } - return image.properties.image_type || - angular.fromJson(image.properties.block_device_mapping)[0].source_type || - 'image'; + if (image.properties.image_type) { + return image.properties.image_type; + } + var bdm = angular.fromJson(image.properties.block_device_mapping || "[]"); + if (bdm[0] && bdm[0].source_type) { + return bdm[0].source_type; + } + return 'image'; } function isValidImage(image) { diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js index fa15af910..27a580698 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js @@ -151,6 +151,8 @@ {id: '4', container_format: 'raw', properties: {}, name: 'raw_image'}, {id: '5', container_format: 'ami', properties: {image_type: 'image'}}, {id: '6', container_format: 'raw', properties: {image_type: 'image'}}, + {id: '11', container_format: 'raw', properties: {image_type: ''}}, + {id: '12', container_format: 'raw', properties: {block_device_mapping: '[]'}}, // The following images are considered as "snapshot" sources. {id: '7', container_format: 'ami', properties: {block_device_mapping: '[{"source_type": "snapshot"}]'}}, @@ -393,6 +395,9 @@ name_or_id: 'raw_image'}, {id: '5', container_format: 'ami', properties: {image_type: 'image'}, name_or_id: '5'}, {id: '6', container_format: 'raw', properties: {image_type: 'image'}, name_or_id: '6'}, + {id: '11', container_format: 'raw', properties: {image_type: ''}, name_or_id: '11'}, + {id: '12', container_format: 'raw', properties: {block_device_mapping: '[]'}, + name_or_id: '12'}, {id: '10', container_format: 'raw', properties: {image_type: 'image'}, name_or_id: '10', visibility: 'community'}, ]; diff --git a/openstack_dashboard/locale/de/LC_MESSAGES/django.po b/openstack_dashboard/locale/de/LC_MESSAGES/django.po index 10d7f5473..44d08e212 100644 --- a/openstack_dashboard/locale/de/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/de/LC_MESSAGES/django.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8895,13 +8895,6 @@ msgstr "z.B. Ja / Nein" msgid "e.g. Yes/No" msgstr "z.B. Ja/Nein" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"Varianten ID darf nur alphanumerische Zeichen, Unterstriche, Punkte, " -"Bindestriche und Leerzeichen enthalten." - msgid "front-end" msgstr "Frontend" diff --git a/openstack_dashboard/locale/en_GB/LC_MESSAGES/django.po b/openstack_dashboard/locale/en_GB/LC_MESSAGES/django.po index a4b427f96..eed773fa6 100644 --- a/openstack_dashboard/locale/en_GB/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/en_GB/LC_MESSAGES/django.po @@ -13,11 +13,11 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-09-21 16:22+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2022-09-24 01:11+0000\n" +"PO-Revision-Date: 2022-11-04 10:35+0000\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" @@ -8801,10 +8801,10 @@ msgstr "e.g. Yes/No" msgid "" "flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." +"hyphens, spaces. Use 'auto' to automatically generate id" msgstr "" -"flavour id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." +"flavour id can only contain alphanumeric characters, underscores, fullstops, " +"hyphens, spaces. Use 'auto' to automatically generate id" msgid "front-end" msgstr "front-end" diff --git a/openstack_dashboard/locale/eo/LC_MESSAGES/django.po b/openstack_dashboard/locale/eo/LC_MESSAGES/django.po index fa44f0cd6..97b576a77 100644 --- a/openstack_dashboard/locale/eo/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/eo/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-09-30 06:37+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8803,13 +8803,6 @@ msgstr "ekz. Jes / Ne" msgid "e.g. Yes/No" msgstr "ekz. Jes/Ne" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -" speco id nur enhavus literciferajn signojn, substrekojn, punktojn," -"dividstrekojn, blankspacojn." - msgid "front-end" msgstr "fasada" diff --git a/openstack_dashboard/locale/es/LC_MESSAGES/django.po b/openstack_dashboard/locale/es/LC_MESSAGES/django.po index 2465a68c0..0dde555aa 100644 --- a/openstack_dashboard/locale/es/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/es/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8974,13 +8974,6 @@ msgstr "e.j Si/ No" msgid "e.g. Yes/No" msgstr "p. ej. Sí/No" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"El id del sabor solo puede contener caracteres alfanuméricos, guiones " -"normales y bajos, puntos y espacios." - msgid "front-end" msgstr "front-end" diff --git a/openstack_dashboard/locale/fr/LC_MESSAGES/django.po b/openstack_dashboard/locale/fr/LC_MESSAGES/django.po index ebf5ca5fe..d23309395 100644 --- a/openstack_dashboard/locale/fr/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/fr/LC_MESSAGES/django.po @@ -26,7 +26,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8546,13 +8546,6 @@ msgstr "ex : Oui / Non" msgid "e.g. Yes/No" msgstr "ex : Oui/Non" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"Un id de gabarit ne peut comporter que des caractères alphanumériques, des " -"soulignés, des points, des traits d'union ou des espaces." - msgid "front-end" msgstr "front-end" diff --git a/openstack_dashboard/locale/id/LC_MESSAGES/django.po b/openstack_dashboard/locale/id/LC_MESSAGES/django.po index bbb4b4cd3..39fd03f21 100644 --- a/openstack_dashboard/locale/id/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/id/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8636,13 +8636,6 @@ msgstr "e.g. Yes / No" msgid "e.g. Yes/No" msgstr "misalnya Ya Tidak" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"flavor id hanya dapat berisi karakter alfanumerik, garis bawah, titik, tanda " -"hubung, spasi." - msgid "front-end" msgstr "front-end" diff --git a/openstack_dashboard/locale/ja/LC_MESSAGES/django.po b/openstack_dashboard/locale/ja/LC_MESSAGES/django.po index 494a7b4e5..42ab9bef8 100644 --- a/openstack_dashboard/locale/ja/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/ja/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-10-13 05:54+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8759,13 +8759,6 @@ msgstr "例: Yes / No" msgid "e.g. Yes/No" msgstr "例: Yes/No" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"フレーバーの ID に使用できるのは、英数字、アンダースコアー、ピリオド、ハイフ" -"ン、空白文字のみです。" - msgid "front-end" msgstr "フロントエンド" diff --git a/openstack_dashboard/locale/ko_KR/LC_MESSAGES/django.po b/openstack_dashboard/locale/ko_KR/LC_MESSAGES/django.po index e3e04e99e..706a335c5 100644 --- a/openstack_dashboard/locale/ko_KR/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/ko_KR/LC_MESSAGES/django.po @@ -30,7 +30,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8487,13 +8487,6 @@ msgstr "예시: Yes / No" msgid "e.g. Yes/No" msgstr "예: Yes/No" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"flavor id는 영숫자 문자, 밑줄, 마침표, 콜론, 하이픈, 스페이스만 포함할 수 있" -"습니다." - msgid "front-end" msgstr "프론트-엔드" diff --git a/openstack_dashboard/locale/pt_BR/LC_MESSAGES/django.po b/openstack_dashboard/locale/pt_BR/LC_MESSAGES/django.po index f7f0d0574..ac89bd3a3 100644 --- a/openstack_dashboard/locale/pt_BR/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/pt_BR/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8245,13 +8245,6 @@ msgstr "i.e. Sim / Não" msgid "e.g. Yes/No" msgstr "i.e. Sim/Não" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"Identificador do sabor pode conter somente caracteres alfanuméricos, " -"sublinhados, pontos, hifens e espaços." - msgid "front-end" msgstr "front-end" diff --git a/openstack_dashboard/locale/ru/LC_MESSAGES/django.po b/openstack_dashboard/locale/ru/LC_MESSAGES/django.po index 2a8916028..b46174599 100644 --- a/openstack_dashboard/locale/ru/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/ru/LC_MESSAGES/django.po @@ -41,7 +41,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-10-13 05:54+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8998,13 +8998,6 @@ msgstr "т.е. Да/Нет" msgid "e.g. Yes/No" msgstr "т.е. Да/Нет" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "" -"Имя типа инстанса может сождержать только алфавитно-цифровые символы, " -"символы подчеркивания, точки, дефисы и пробелы." - msgid "front-end" msgstr "фронтэнд" diff --git a/openstack_dashboard/locale/zh_Hans/LC_MESSAGES/django.po b/openstack_dashboard/locale/zh_Hans/LC_MESSAGES/django.po index ce4484d82..b6ee05bef 100644 --- a/openstack_dashboard/locale/zh_Hans/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/zh_Hans/LC_MESSAGES/django.po @@ -33,7 +33,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -8188,11 +8188,6 @@ msgstr "例如,Yes / No" msgid "e.g. Yes/No" msgstr "例如,是/否" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "实例类型 id 只能包含字母数字字符、下划线、句点、连字符和空格。" - msgid "front-end" msgstr "前端" diff --git a/openstack_dashboard/locale/zh_Hant/LC_MESSAGES/django.po b/openstack_dashboard/locale/zh_Hant/LC_MESSAGES/django.po index 944f6053d..444b28889 100644 --- a/openstack_dashboard/locale/zh_Hant/LC_MESSAGES/django.po +++ b/openstack_dashboard/locale/zh_Hant/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: horizon VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2022-06-21 10:46+0000\n" +"POT-Creation-Date: 2022-11-04 11:42+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -7796,11 +7796,6 @@ msgstr "例如:Yes/No" msgid "e.g. Yes/No" msgstr "例如:Yes/No" -msgid "" -"flavor id can only contain alphanumeric characters, underscores, periods, " -"hyphens, spaces." -msgstr "樣板 ID 名稱只能包含英數字元、底線、句點、連字號及空白鍵。" - msgid "front-end" msgstr "前端" diff --git a/openstack_dashboard/test/integration_tests/basewebobject.py b/openstack_dashboard/test/integration_tests/basewebobject.py index aae87e910..f4207b0ce 100644 --- a/openstack_dashboard/test/integration_tests/basewebobject.py +++ b/openstack_dashboard/test/integration_tests/basewebobject.py @@ -152,6 +152,13 @@ class BaseWebObject(unittest.TestCase): # it will raise the NoSuchElementException exception. pass + def wait_until_element_is_visible(self, locator): + with self.waits_disabled(): + try: + self._wait_till_element_visible(locator) + except Exceptions.NoSuchElementException: + pass + def wait_till_spinner_disappears(self): def getter(): return self.driver.find_element(*self._spinner_locator) diff --git a/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py b/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py index 117c64b5c..0c61bfcea 100644 --- a/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py +++ b/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py @@ -117,6 +117,14 @@ class ImagesPage(basepage.BaseNavigationPage): 'hz-magic-search-bar span.fa-search') _search_option_locator = (by.By.CSS_SELECTOR, 'magic-search.form-control span.search-entry') + _search_name_locator_filled = ( + by.By.XPATH, + "//*[@id='imageForm-name'][contains(@class,'ng-not-empty')]" + ) + _search_checkbox_loaded = ( + by.By.CSS_SELECTOR, + "td .themable-checkbox [type='checkbox'] + label[for*='Zactive']" + ) def __init__(self, driver, conf): super().__init__(driver, conf) @@ -134,6 +142,8 @@ class ImagesPage(basepage.BaseNavigationPage): return self._get_element(*self._default_form_locator) def _get_row_with_image_name(self, name): + self.wait_until_element_is_visible(self._search_checkbox_loaded) + return self.images_table.get_row(IMAGES_TABLE_NAME_COLUMN, name) def create_image(self, name, description=None, @@ -178,6 +188,7 @@ class ImagesPage(basepage.BaseNavigationPage): visibility=None, protected=None): row = self._get_row_with_image_name(name) confirm_edit_images_form = self.images_table.edit_image(row) + self.wait_until_element_is_visible(self._search_name_locator_filled) if new_name is not None: confirm_edit_images_form.name.text = new_name diff --git a/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py b/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py index 2293abec1..236d9465d 100644 --- a/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py +++ b/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. import netaddr +from selenium.common import exceptions from selenium.webdriver.common import by from openstack_dashboard.test.integration_tests.pages import basepage @@ -64,6 +65,11 @@ class InstancesPage(basepage.BaseNavigationPage): FLAVOR_STEP_INDEX = 2 NETWORKS_STEP_INDEX = 3 + _search_state_active = ( + by.By.XPATH, + "//*[contains(@class,'normal_column')][contains(text(),'Active')]" + ) + def __init__(self, driver, conf): super().__init__(driver, conf) self._page_title = "Instances" @@ -155,6 +161,10 @@ class InstancesPage(basepage.BaseNavigationPage): row = self._get_row_with_instance_name(name) return row and row.cells[self.INSTANCES_TABLE_STATUS_COLUMN] + try: + self.wait_until_element_is_visible(self._search_state_active) + except exceptions.TimeoutException: + return False status = self.instances_table.wait_cell_status(cell_getter, ('Active', 'Error')) return status == 'Active' diff --git a/openstack_dashboard/test/test_data/neutron_data.py b/openstack_dashboard/test/test_data/neutron_data.py index 7ac5eafb1..78bd93df3 100644 --- a/openstack_dashboard/test/test_data/neutron_data.py +++ b/openstack_dashboard/test/test_data/neutron_data.py @@ -222,6 +222,26 @@ def data(TEST): TEST.api_ports.add(port_dict) TEST.ports.add(neutron.Port(port_dict)) + # unbound port on 1st network + port_dict = { + 'admin_state_up': True, + 'device_id': '', + 'device_owner': '', + 'fixed_ips': [{'ip_address': '10.0.0.5', + 'subnet_id': subnet_dict['id']}], + 'id': 'a5aa0d62-cd5f-4e7d-b022-4ff63f981bcd', + 'mac_address': 'fa:16:3e:ce:e0:f8', + 'name': '', + 'network_id': network_dict['id'], + 'status': 'DOWN', + 'tenant_id': network_dict['tenant_id'], + 'binding:vnic_type': 'normal', + 'binding:host_id': '', + 'security_groups': [], + } + TEST.api_ports.add(port_dict) + TEST.ports.add(neutron.Port(port_dict)) + # 2nd network. network_dict = {'admin_state_up': True, 'id': '72c3ab6c-c80f-4341-9dc5-210fa31ac6c2', diff --git a/openstack_dashboard/test/unit/api/test_neutron.py b/openstack_dashboard/test/unit/api/test_neutron.py index 5eb6bbd7b..19bde8df1 100644 --- a/openstack_dashboard/test/unit/api/test_neutron.py +++ b/openstack_dashboard/test/unit/api/test_neutron.py @@ -2488,9 +2488,11 @@ class NeutronApiFloatingIpTests(test.APIMockTestCase): return '%(id)s_%(addr)s' % param def _get_target_name(self, port, ip=None): - param = {'svrid': port['device_id'], - 'addr': ip or port['fixed_ips'][0]['ip_address']} - return 'server_%(svrid)s: %(addr)s' % param + ip_address = ip or port['fixed_ips'][0]['ip_address'] + if port['device_id']: + return 'server_%s: %s' % (port['device_id'], ip_address) + else: + return ip_address @override_settings( OPENSTACK_NEUTRON_NETWORK={ diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po index a28cd44b1..0dd0d778a 100644 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po @@ -9,11 +9,11 @@ msgid "" msgstr "" "Project-Id-Version: horizon\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-21 16:17+0000\n" +"POT-Creation-Date: 2022-11-04 11:39+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2022-09-24 01:10+0000\n" +"PO-Revision-Date: 2022-11-04 10:35+0000\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" @@ -168,8 +168,8 @@ msgstr "18.3.0" msgid "18.3.3" msgstr "18.3.3" -msgid "18.3.5-4" -msgstr "18.3.5-4" +msgid "18.3.5-6" +msgstr "18.3.5-6" msgid "18.5.0" msgstr "18.5.0" @@ -106,7 +106,7 @@ setenv = SELENIUM_HEADLESS=False commands = oslo-config-generator --namespace openstack_dashboard_integration_tests - pytest --ds=openstack_dashboard.test.settings -v --junitxml="{toxinidir}/test_reports/integration_test_results.xml" --html="{toxinidir}/test_reports/integration_test_results.html" --self-contained-html {posargs:{toxinidir}/openstack_dashboard/test/integration_tests} + pytest --ds=openstack_dashboard.test.settings -v -x --junitxml="{toxinidir}/test_reports/integration_test_results.xml" --html="{toxinidir}/test_reports/integration_test_results.html" --self-contained-html {posargs:{toxinidir}/openstack_dashboard/test/integration_tests} [testenv:npm] passenv = |