From 9a9772ab80318d8fa88600dcc719f178fdd318a2 Mon Sep 17 00:00:00 2001 From: mavinagi Date: Wed, 2 Sep 2015 19:04:02 -0500 Subject: [PATCH] Handle Volume launch as instance(NG) in Volume tables. The launch as instance option for Volumes launches the legacy launch instance wizard even if local_settings is configured for LAUNCH_INSTANCE_LEGACY_ENABLED = False. This Fix addresses the issue. Volume snapshots will be a separate patch. Horizon tables.js has a separate bug that needs to be fixed: https://bugs.launchpad.net/horizon/+bug/1514627 Change-Id: Id4a7dc2a48c63cbe27ece4dba1825eb89b7a0388 Closes-bug: #1491645 Co-Authored-By: Travis Tripp --- .../source/source.controller.js | 25 +++++++++++ .../source/source.controller.spec.js | 17 ++++++-- .../project/volumes/volumes/tables.py | 41 +++++++++++++++++-- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.js index 928c608063..7f34a194a7 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.js @@ -328,11 +328,27 @@ } ); + var volumeWatcher = $scope.$watchCollection( + function getVolumes() { + return $scope.model.volumes; + }, + function onVolumesChange() { + $scope.initPromise.then(function onInit() { + $scope.$applyAsync(function setDefaultVolume() { + if ($scope.launchContext.volumeId) { + setSourceVolumeWithId($scope.launchContext.volumeId); + } + }); + }); + } + ); + // Explicitly remove watchers on desruction of this controller $scope.$on('$destroy', function() { newSpecWatcher(); allocatedWatcher(); imagesWatcher(); + volumeWatcher(); }); // Initialize @@ -458,5 +474,14 @@ ctrl.currentBootSource = ctrl.bootSourcesOptions[0].type; } } + + function setSourceVolumeWithId(id) { + var pre = findSourceById($scope.model.volumes, id); + if (pre) { + changeBootSource(bootSourceTypes.VOLUME, [pre]); + $scope.model.newInstanceSpec.source_type = ctrl.bootSourcesOptions[2]; + ctrl.currentBootSource = ctrl.bootSourcesOptions[2].type; + } + } } })(); diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.spec.js index 065f92cb3d..fbc6afb9f9 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/source/source.controller.spec.js @@ -49,7 +49,7 @@ newInstanceSpec: { source: [], source_type: '' }, images: [ { id: 'image-1' }, { id: 'image-2' } ], imageSnapshots: [], - volumes: [], + volumes: [ { id: 'volume-1' }, { id: 'volume-2' } ], volumeSnapshots: [], novaLimits: { maxTotalInstances: 10, @@ -186,15 +186,26 @@ }); }); + it('defaults source to volume-2 if launchContext.volumeId = volume-2', function() { + scope.launchContext = { volumeId: 'volume-2' }; + deferred.resolve(); + + $browser.defer.flush(); + + expect(ctrl.tableData.allocated[0]).toEqual({ id: 'volume-2' }); + expect(scope.model.newInstanceSpec.source_type.type).toBe('volume'); + expect(ctrl.currentBootSource).toBe('volume'); + }); + describe('Scope Functions', function() { describe('watchers', function () { it('establishes three watches', function() { - expect(scope.$watch.calls.count()).toBe(3); + expect(scope.$watch.calls.count()).toBe(4); }); it("establishes one watch collections", function () { - expect(scope.$watchCollection.calls.count()).toBe(1); + expect(scope.$watchCollection.calls.count()).toBe(2); }); }); diff --git a/openstack_dashboard/dashboards/project/volumes/volumes/tables.py b/openstack_dashboard/dashboards/project/volumes/volumes/tables.py index 756e8dd574..29eedb494f 100644 --- a/openstack_dashboard/dashboards/project/volumes/volumes/tables.py +++ b/openstack_dashboard/dashboards/project/volumes/volumes/tables.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from django.conf import settings from django.core.urlresolvers import NoReverseMatch # noqa from django.core.urlresolvers import reverse from django.http import HttpResponse # noqa @@ -62,6 +63,30 @@ class LaunchVolume(tables.LinkAction): return False +class LaunchVolumeNG(LaunchVolume): + name = "launch_volume_ng" + verbose_name = _("Launch as Instance") + url = "horizon:project:volumes:index" + classes = ("btn-launch", ) + ajax = False + + def __init__(self, attrs=None, **kwargs): + kwargs['preempt'] = True + super(LaunchVolume, self).__init__(attrs, **kwargs) + + def get_link_url(self, datum): + url = reverse(self.url) + vol_id = "%s:vol" % self.table.get_object_id(datum) + ngclick = "modal.openLaunchInstanceWizard(" \ + "{successUrl: '%s', volumeId: '%s'})" \ + % (url, vol_id.split(":vol")[0]) + self.attrs.update({ + "ng-controller": "LaunchInstanceModalController as modal", + "ng-click": ngclick + }) + return "javascript:void(0);" + + class DeleteVolume(VolumePolicyTargetMixin, tables.DeleteAction): @staticmethod def action_present(count): @@ -450,10 +475,18 @@ class VolumesTable(VolumesTableBase): row_class = UpdateRow table_actions = (CreateVolume, AcceptTransfer, DeleteVolume, VolumesFilterAction) - row_actions = (EditVolume, ExtendVolume, LaunchVolume, EditAttachments, - CreateSnapshot, CreateBackup, RetypeVolume, - UploadToImage, CreateTransfer, DeleteTransfer, - DeleteVolume) + + launch_actions = () + if getattr(settings, 'LAUNCH_INSTANCE_LEGACY_ENABLED', False): + launch_actions = (LaunchVolume,) + launch_actions + if getattr(settings, 'LAUNCH_INSTANCE_NG_ENABLED', True): + launch_actions = (LaunchVolumeNG,) + launch_actions + + row_actions = ((EditVolume, ExtendVolume,) + + launch_actions + + (EditAttachments, CreateSnapshot, CreateBackup, + RetypeVolume, UploadToImage, CreateTransfer, + DeleteTransfer, DeleteVolume)) class DetachVolume(tables.BatchAction):