diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/flavor/flavor.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/flavor/flavor.spec.js
index c388fb032d..c8863a2ed3 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/flavor/flavor.spec.js
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/flavor/flavor.spec.js
@@ -35,6 +35,7 @@
model = { newInstanceSpec: { },
novaLimits: { },
+ cinderLimits: { },
flavors: []
};
defaults = { usageLabel: "label",
@@ -54,7 +55,10 @@
it('defines expected labels', function () {
var props = [
'chartTotalInstancesLabel',
- 'chartTotalVcpusLabel', 'chartTotalRamLabel'
+ 'chartTotalVcpusLabel',
+ 'chartTotalRamLabel',
+ 'chartTotalVolumeLabel',
+ 'chartTotalVolumeStorageLabel'
];
props.forEach(function (prop) {
@@ -75,6 +79,11 @@
});
});
+ it('includes the unit if it is provided', function () {
+ var data = ctrl.getChartData('fakeTitle', 1, 2, 3, "MB");
+ expect(data.unit).toBe('MB');
+ });
+
describe("watches", function () {
beforeEach(function() {
@@ -93,14 +102,14 @@
ctrl.validateFlavor.calls.reset();
});
- it("establishes five watches", function () {
+ it("establishes seven watches", function () {
// Count calls to $watch (note: $watchCollection
// also calls $watch)
- expect(scope.$watch.calls.count()).toBe(5);
+ expect(scope.$watch.calls.count()).toBe(7);
});
- it("establishes three watch collections", function () {
- expect(scope.$watchCollection.calls.count()).toBe(3);
+ it("establishes four watch collections", function () {
+ expect(scope.$watchCollection.calls.count()).toBe(4);
});
describe("novaLimits watch", function () {
@@ -245,6 +254,40 @@
});
});
+ describe("cinderLimits watcher", function () {
+
+ it("initializes cinderLimits", function () {
+ expect(ctrl.cinderLimits).toEqual({});
+ });
+
+ it("should call updateFlavorFacades", function () {
+ model.cinderLimits = {test: "test"};
+ scope.$apply();
+ expect(ctrl.cinderLimits).toEqual({test: "test"});
+ expect(ctrl.updateFlavorFacades.calls.count()).toBe(1);
+ });
+ });
+
+ describe("volume size watcher", function () {
+
+ it("should call updateFlavorFacades when source type is changed", function () {
+ model.newInstanceSpec.source_type = "image";
+ scope.$apply();
+ expect(ctrl.updateFlavorFacades.calls.count()).toBe(1);
+ });
+
+ it("should call updateFlavorFacades when volume size is changed", function () {
+ model.newInstanceSpec.vol_size = 10;
+ scope.$apply();
+ expect(ctrl.updateFlavorFacades.calls.count()).toBe(1);
+ });
+
+ it("should call updateFlavorFacades when volume create is changed", function () {
+ model.newInstanceSpec.vol_create = true;
+ scope.$apply();
+ expect(ctrl.updateFlavorFacades.calls.count()).toBe(1);
+ });
+ });
});
describe("when having allocated flavors", function () {
@@ -412,6 +455,36 @@
});
});
+ describe("test updateFlavorFacades", function () {
+
+ beforeEach(function () {
+ ctrl.flavors = [{name: "tiny"}];
+ });
+
+ it("should set volumeChartData and volumeStorageChartData", function () {
+ ctrl.updateFlavorFacades();
+ expect(ctrl.availableFlavorFacades.length).toBe(1);
+ expect(ctrl.availableFlavorFacades[0].volumeChartData).toBeDefined();
+ expect(ctrl.availableFlavorFacades[0].volumeStorageChartData).toBeDefined();
+ });
+
+ it("should call getChartData", function() {
+ spyOn(ctrl, 'getChartData');
+ ctrl.updateFlavorFacades();
+ expect(ctrl.getChartData.calls.count()).toBe(5);
+ });
+ });
+
+ describe("test validateFlavor", function () {
+
+ it("should call validateFlavor when source type is changed", function () {
+ spyOn(ctrl, 'validateFlavor');
+ model.newInstanceSpec.source_type = "image";
+ scope.$apply();
+ expect(ctrl.validateFlavor.calls.count()).toBe(1);
+ });
+ });
+
});
});
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 2d2e3b86af..f9b2bab6b3 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
@@ -561,6 +561,7 @@
function addVolumeSourcesIfEnabled(config) {
var volumeDeferred = $q.defer();
var volumeSnapshotDeferred = $q.defer();
+ var absoluteLimitsDeferred = $q.defer();
serviceCatalog
.ifTypeEnabled('volumev2')
.then(onVolumeServiceEnabled, onCheckVolumeV3);
@@ -576,8 +577,10 @@
.then(onBootToVolumeSupported);
if (!config || !config.disable_volume) {
getVolumes().then(resolveVolumes, failVolumes);
+ getAbsoluteLimits().then(resolveAbsoluteLimitsDeferred, resolveAbsoluteLimitsDeferred);
} else {
resolveVolumes();
+ resolveAbsoluteLimitsDeferred();
}
if (!config || !config.disable_volume_snapshot) {
getVolumeSnapshots().then(resolveVolumeSnapshots, failVolumeSnapshots);
@@ -592,6 +595,9 @@
return cinderAPI.getVolumes({status: 'available', bootable: 1})
.then(onGetVolumes);
}
+ function getAbsoluteLimits() {
+ return cinderAPI.getAbsoluteLimits().then(onGetCinderLimits);
+ }
function getVolumeSnapshots() {
return cinderAPI.getVolumeSnapshots({status: 'available'})
.then(onGetVolumeSnapshots);
@@ -599,6 +605,7 @@
function resolvePromises() {
volumeDeferred.resolve();
volumeSnapshotDeferred.resolve();
+ absoluteLimitsDeferred.resolve();
}
function resolveVolumes() {
volumeDeferred.resolve();
@@ -612,10 +619,14 @@
function failVolumeSnapshots() {
volumeSnapshotDeferred.resolve();
}
+ function resolveAbsoluteLimitsDeferred() {
+ absoluteLimitsDeferred.resolve();
+ }
return $q.all(
[
volumeDeferred.promise,
- volumeSnapshotDeferred.promise
+ volumeSnapshotDeferred.promise,
+ absoluteLimitsDeferred.promise
]);
}
@@ -743,6 +754,12 @@
finalSpec.source_id = '';
}
+ // Cinder Limits
+
+ function onGetCinderLimits(response) {
+ model.cinderLimits = response.data;
+ }
+
// Nova Limits
function onGetNovaLimits(data) {
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 1a5db23afb..23d3f742ba 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
@@ -232,6 +232,15 @@
var deferred = $q.defer();
deferred.resolve({ data: { items: snapshots } });
+ return deferred.promise;
+ },
+ getAbsoluteLimits: function() {
+ var limits = { maxTotalVolumes: 100,
+ totalVolumesUsed: 2,
+ maxTotalVolumeGigabytes: 1000,
+ totalGigabytesUsed: 10 };
+ var deferred = $q.defer();
+ deferred.resolve({ data: limits });
return deferred.promise;
}
});
@@ -732,6 +741,16 @@
expect(model.allowedBootSources).toContain(VOLUME_SNAPSHOT);
});
+ it('should have maxTotalVolumes and maxTotalVolumeGigabytes if cinder ' +
+ 'is enabled', function() {
+ cinderEnabled = true;
+ model.initialize(true);
+ scope.$apply();
+
+ expect(model.cinderLimits.maxTotalVolumes).toBe(100);
+ expect(model.cinderLimits.maxTotalVolumeGigabytes).toBe(1000);
+ });
+
});
describe('Post Initialization Model - Initializing', function() {
diff --git a/openstack_dashboard/static/dashboard/scss/components/_transfer_tables.scss b/openstack_dashboard/static/dashboard/scss/components/_transfer_tables.scss
index a677cd91fc..8999605ec9 100644
--- a/openstack_dashboard/static/dashboard/scss/components/_transfer_tables.scss
+++ b/openstack_dashboard/static/dashboard/scss/components/_transfer_tables.scss
@@ -10,6 +10,10 @@
.transfer-section {
margin-top: $padding-large-vertical;
+
+ .row .pie-chart {
+ margin-top: 10px;
+ }
}
.magic-search-bar, .basic-search-bar {
diff --git a/releasenotes/notes/bp-launch-instance-volume-quotas-490070a36cadfe8d.yaml b/releasenotes/notes/bp-launch-instance-volume-quotas-490070a36cadfe8d.yaml
new file mode 100644
index 0000000000..d311a4de73
--- /dev/null
+++ b/releasenotes/notes/bp-launch-instance-volume-quotas-490070a36cadfe8d.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - Added two charts to show the Number of Volumes and Total Volume Storage
+ quotas on launch instance modal when cinder is enabled.