diff --git a/horizon/dashboards/nova/volumes/forms.py b/horizon/dashboards/nova/volumes/forms.py index 2e15cf5ef..650050968 100644 --- a/horizon/dashboards/nova/volumes/forms.py +++ b/horizon/dashboards/nova/volumes/forms.py @@ -7,6 +7,7 @@ Views for managing Nova volumes. """ +from django.conf import settings from django.core.urlresolvers import reverse from django.forms import ValidationError from django.utils.translation import ugettext_lazy as _ @@ -126,6 +127,15 @@ class AttachForm(forms.SelfHandlingForm): def __init__(self, *args, **kwargs): super(AttachForm, self).__init__(*args, **kwargs) + + # Hide the device field if the hypervisor doesn't support it. + hypervisor_features = getattr(settings, + "OPENSTACK_HYPERVISOR_FEATURES", + {}) + can_set_mount_point = hypervisor_features.get("can_set_mount_point", + True) + if not can_set_mount_point: + self.fields['device'].widget = forms.widgets.HiddenInput() # populate volume_id volume = kwargs.get('initial', {}).get("volume", None) if volume: diff --git a/horizon/dashboards/nova/volumes/tests.py b/horizon/dashboards/nova/volumes/tests.py index c8a0dda4e..396135a46 100644 --- a/horizon/dashboards/nova/volumes/tests.py +++ b/horizon/dashboards/nova/volumes/tests.py @@ -19,7 +19,9 @@ # under the License. from django import http +from django.conf import settings from django.core.urlresolvers import reverse +from django.forms import widgets from mox import IsA from horizon import api @@ -183,20 +185,40 @@ class VolumeViewTests(test.TestCase): volume = self.volumes.first() servers = self.servers.list() - api.volume_get(IsA(http.HttpRequest), volume.id) \ - .AndReturn(volume) + api.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume) api.nova.server_list(IsA(http.HttpRequest)).AndReturn(servers) - self.mox.ReplayAll() - url = reverse('horizon:nova:volumes:attach', - args=[volume.id]) + url = reverse('horizon:nova:volumes:attach', args=[volume.id]) res = self.client.get(url) # Asserting length of 2 accounts for the one instance option, # and the one 'Choose Instance' option. - self.assertEqual(len(res.context['form'].fields['instance']._choices), + form = res.context['form'] + self.assertEqual(len(form.fields['instance']._choices), 2) self.assertEqual(res.status_code, 200) + self.assertTrue(isinstance(form.fields['device'].widget, + widgets.TextInput)) + + @test.create_stubs({api: ('volume_get',), api.nova: ('server_list',)}) + def test_edit_attachments_cannot_set_mount_point(self): + PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_set_mount_point'] + settings.OPENSTACK_HYPERVISOR_FEATURES['can_set_mount_point'] = False + + volume = self.volumes.first() + servers = self.servers.list() + + api.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume) + api.nova.server_list(IsA(http.HttpRequest)).AndReturn(servers) + self.mox.ReplayAll() + + url = reverse('horizon:nova:volumes:attach', args=[volume.id]) + res = self.client.get(url) + # Assert the device field is hidden. + form = res.context['form'] + self.assertTrue(isinstance(form.fields['device'].widget, + widgets.HiddenInput)) + settings.OPENSTACK_HYPERVISOR_FEATURES['can_set_mount_point'] = PREV @test.create_stubs({api: ('volume_get',), api.nova: ('server_get', 'server_list',)}) diff --git a/horizon/tests/testsettings.py b/horizon/tests/testsettings.py index 643ce47ef..26498b6d1 100644 --- a/horizon/tests/testsettings.py +++ b/horizon/tests/testsettings.py @@ -141,6 +141,10 @@ OPENSTACK_KEYSTONE_BACKEND = { 'can_edit_user': True } +OPENSTACK_HYPERVISOR_FEATURES = { + 'can_set_mount_point': True +} + LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example index fa3693689..0a6e54662 100644 --- a/openstack_dashboard/local/local_settings.py.example +++ b/openstack_dashboard/local/local_settings.py.example @@ -74,6 +74,10 @@ OPENSTACK_KEYSTONE_BACKEND = { 'can_edit_user': True } +OPENSTACK_HYPERVISOR_FEATURES = { + 'can_set_mount_point': True +} + # OPENSTACK_ENDPOINT_TYPE specifies the endpoint type to use for the endpoints # in the Keystone service catalog. Use this setting when Horizon is running # external to the OpenStack environment. The default is 'internalURL'.