Merge "Add charts to show volume quotas on Python launch instance modal"
This commit is contained in:
commit
ccfa52fad1
@ -71,6 +71,36 @@
|
||||
</div>
|
||||
{{ endminifyspace }}
|
||||
|
||||
{% if cinder_enabled %}
|
||||
<div class="quota_title">
|
||||
<strong class="pull-left">{% trans "Number of Volumes" %}</strong>
|
||||
{% blocktrans with used=usages.totalVolumesUsed|intcomma quota=usages.maxTotalVolumes|intcomma|quotainf %}
|
||||
<span class="pull-right">{{ used }} of {{ quota }} Used</span>{% endblocktrans %}
|
||||
</div>
|
||||
<div id="quota_volume"
|
||||
class="quota_bar"
|
||||
data-progress-indicator-flavor
|
||||
data-quota-limit="{{ usages.maxTotalVolumes }}"
|
||||
data-quota-used="{{ usages.totalVolumesUsed }}">
|
||||
{% widthratio usages.totalVolumesUsed usages.maxTotalVolumes 100 as volume_percent %}
|
||||
{% bs_progress_bar volume_percent 0 %}
|
||||
</div>
|
||||
|
||||
<div class="quota_title">
|
||||
<strong class="pull-left">{% trans "Total Volume Storage" %}</strong>
|
||||
{% blocktrans with used=usages.gigabytesUsed|intcomma quota=usages.maxTotalVolumeGigabytes|intcomma|quotainf %}
|
||||
<span class="pull-right">{{ used }} of {{ quota }} GiB Used</span>{% endblocktrans %}
|
||||
</div>
|
||||
<div id="quota_volume_storage"
|
||||
class="quota_bar"
|
||||
data-progress-indicator-flavor
|
||||
data-quota-limit="{{ usages.maxTotalVolumeGigabytes }}"
|
||||
data-quota-used="{{ usages.gigabytesUsed }}">
|
||||
{% widthratio usages.gigabytesUsed usages.maxTotalVolumeGigabytes 100 as volume_storage_percent %}
|
||||
{% bs_progress_bar volume_storage_percent 0 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -1559,7 +1559,6 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_snapshot_list',
|
||||
@ -1567,7 +1566,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'profile_list',
|
||||
'port_list'),
|
||||
api.glance: ('image_list_detailed',)})
|
||||
api.glance: ('image_list_detailed',),
|
||||
quotas: ('tenant_limit_usages',)})
|
||||
def test_launch_instance_get(self,
|
||||
expect_password_fields=True,
|
||||
block_device_mapping_v2=True,
|
||||
@ -1628,7 +1628,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'ServerGroups', IsA(http.HttpRequest)).AndReturn(True)
|
||||
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.server_groups.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True)\
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest))\
|
||||
.AndReturn(self.limits['absolute'])
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -1805,7 +1805,6 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_snapshot_list',
|
||||
@ -1813,7 +1812,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'profile_list',
|
||||
'port_list'),
|
||||
api.glance: ('image_list_detailed',)})
|
||||
api.glance: ('image_list_detailed',),
|
||||
quotas: ('tenant_limit_usages',)})
|
||||
def test_launch_instance_get_bootable_volumes(self,
|
||||
block_device_mapping_v2=True,
|
||||
only_one_network=False,
|
||||
@ -1869,7 +1869,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'ServerGroups', IsA(http.HttpRequest)).AndReturn(True)
|
||||
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.server_groups.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True)\
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest))\
|
||||
.AndReturn(self.limits['absolute'])
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -2338,8 +2338,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
'server_group_list',
|
||||
'tenant_absolute_limits',),
|
||||
'server_group_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
@ -2461,12 +2460,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
'tenant_absolute_limits',),
|
||||
'availability_zone_list'),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_quota_usages',
|
||||
'tenant_limit_usages')})
|
||||
def test_launch_instance_post_no_images_available(self,
|
||||
test_with_profile=False):
|
||||
flavor = self.flavors.first()
|
||||
@ -2482,8 +2481,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
.AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest))\
|
||||
.AndReturn(self.limits['absolute'])
|
||||
|
||||
self._mock_glance_image_list_detailed([])
|
||||
self._mock_neutron_network_and_port_list()
|
||||
@ -2702,7 +2701,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'tenant_absolute_limits'),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
'volume_snapshot_list',
|
||||
'tenant_absolute_limits'),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
def test_launch_instance_post_boot_from_snapshot_error(
|
||||
self,
|
||||
@ -2775,8 +2775,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',)})
|
||||
'availability_zone_list',),
|
||||
quotas: ('tenant_limit_usages',)})
|
||||
def test_launch_flavorlist_error(self,
|
||||
test_with_profile=False):
|
||||
api.nova.extension_supported('BlockDeviceMappingV2Boot',
|
||||
@ -2803,7 +2803,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
IsA(http.HttpRequest)).AndReturn(True)
|
||||
api.nova.extension_supported('ServerGroups',
|
||||
IsA(http.HttpRequest)).AndReturn(False)
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
@ -2971,12 +2971,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_limit_usages',
|
||||
'tenant_quota_usages')})
|
||||
def test_launch_form_instance_count_error(self,
|
||||
test_with_profile=False):
|
||||
flavor = self.flavors.first()
|
||||
@ -3015,8 +3015,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3056,12 +3056,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_quota_usages',
|
||||
'tenant_limit_usages')})
|
||||
def _test_launch_form_count_error(self, resource,
|
||||
avail, test_with_profile=False):
|
||||
flavor = self.flavors.first()
|
||||
@ -3107,8 +3107,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3171,12 +3171,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_quota_usages',
|
||||
'tenant_limit_usages')})
|
||||
def _test_launch_form_instance_requirement_error(self, image, flavor,
|
||||
test_with_profile=False,
|
||||
keypair_require=False):
|
||||
@ -3191,7 +3191,6 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
self._mock_nova_glance_neutron_lists()
|
||||
|
||||
if test_with_profile:
|
||||
policy_profiles = self.policy_profiles.list()
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
@ -3214,8 +3213,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3294,12 +3293,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_quota_usages',
|
||||
'tenant_limit_usages')})
|
||||
def _test_launch_form_instance_show_device_name(self, device_name,
|
||||
widget_class,
|
||||
widget_attrs):
|
||||
@ -3367,9 +3366,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
.AndReturn([])
|
||||
api.nova.flavor_list(
|
||||
IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(
|
||||
IsA(http.HttpRequest), reserved=True
|
||||
).AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(
|
||||
IsA(http.HttpRequest)).AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_quota_usages(
|
||||
IsA(http.HttpRequest)).AndReturn(quota_usages)
|
||||
api.nova.flavor_list(
|
||||
@ -3440,12 +3438,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
'tenant_absolute_limits',
|
||||
'availability_zone_list',),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_list',
|
||||
'volume_snapshot_list',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
quotas: ('tenant_quota_usages',
|
||||
'tenant_limit_usages')})
|
||||
def _test_launch_form_instance_volume_size(self, image, volume_size, msg,
|
||||
test_with_profile=False,
|
||||
volumes=None):
|
||||
@ -3501,7 +3499,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
@ -3806,15 +3804,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
'tenant_absolute_limits',),
|
||||
'availability_zone_list'),
|
||||
api.network: ('security_group_list',),
|
||||
cinder: ('volume_snapshot_list',
|
||||
'volume_list',),
|
||||
api.neutron: ('network_list',
|
||||
'profile_list',
|
||||
'port_list'),
|
||||
api.glance: ('image_list_detailed',)})
|
||||
api.glance: ('image_list_detailed',),
|
||||
quotas: ('tenant_limit_usages',)})
|
||||
def test_select_default_keypair_if_only_one(self,
|
||||
test_with_profile=False):
|
||||
keypair = self.keypairs.first()
|
||||
@ -3833,11 +3831,10 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
policy_profiles = self.policy_profiles.list()
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'policy').AndReturn(policy_profiles)
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
|
||||
.AndReturn(self.limits['absolute'])
|
||||
quotas.tenant_limit_usages(IsA(http.HttpRequest))\
|
||||
.AndReturn(self.limits['absolute'])
|
||||
api.nova.extension_supported('BlockDeviceMappingV2Boot',
|
||||
IsA(http.HttpRequest)) \
|
||||
.AndReturn(True)
|
||||
IsA(http.HttpRequest)).AndReturn(True)
|
||||
api.nova.extension_supported('DiskConfig',
|
||||
IsA(http.HttpRequest)) \
|
||||
.AndReturn(True)
|
||||
|
@ -389,9 +389,10 @@ class SetInstanceDetailsAction(workflows.Action):
|
||||
def get_help_text(self, extra_context=None):
|
||||
extra = {} if extra_context is None else dict(extra_context)
|
||||
try:
|
||||
extra['usages'] = api.nova.tenant_absolute_limits(self.request,
|
||||
reserved=True)
|
||||
extra['usages'] = quotas.tenant_limit_usages(self.request)
|
||||
extra['usages_json'] = json.dumps(extra['usages'])
|
||||
extra['cinder_enabled'] = \
|
||||
base.is_service_enabled(self.request, 'volume')
|
||||
flavors = json.dumps([f._info for f in
|
||||
instance_utils.flavor_list(self.request)])
|
||||
extra['flavors'] = flavors
|
||||
|
@ -323,6 +323,8 @@ horizon.Quota = {
|
||||
$(this.flavor_progress_bars).each(function(index, element) {
|
||||
var element_id = $(element).attr('id');
|
||||
var progress_stat = element_id.match(/^quota_(.+)/)[1];
|
||||
var sourceType = $("#id_source_type").val();
|
||||
var createVolume = (sourceType === "volume_snapshot_id" || sourceType === "volume_image_id");
|
||||
|
||||
if (!progress_stat) {
|
||||
return;
|
||||
@ -352,6 +354,23 @@ horizon.Quota = {
|
||||
var old_ram = scope.old_flavor.ram;
|
||||
var new_ram = scope.selected_flavor.ram;
|
||||
update_amount = (new_ram - old_ram < 0) ? 0 : (new_ram - old_ram);
|
||||
} else if (progress_stat === "volume") {
|
||||
update_amount = createVolume ? instance_count : 0;
|
||||
} else if (progress_stat === "volume_storage") {
|
||||
var volumeSize = 0;
|
||||
|
||||
if (sourceType === "volume_snapshot_id") {
|
||||
// get volume size from the selected snapshot
|
||||
var volumeSizeMatches = $("#id_volume_snapshot_id").children(":selected").html().match(/\s(\d+)\s/g);
|
||||
volumeSize = horizon.Quota.getSelectedFlavor().disk; // set volume size as the minimum flavor size
|
||||
if(volumeSizeMatches) {
|
||||
volumeSize = Math.max(volumeSize, volumeSizeMatches[volumeSizeMatches.length - 1]);
|
||||
}
|
||||
} else if (sourceType === "volume_image_id") {
|
||||
volumeSize = $("#id_volume_size").val();
|
||||
}
|
||||
|
||||
update_amount = volumeSize * instance_count;
|
||||
} else if (scope.selected_flavor) {
|
||||
update_amount = (scope.selected_flavor[progress_stat] * instance_count);
|
||||
}
|
||||
@ -436,10 +455,18 @@ horizon.Quota = {
|
||||
scope.disableFlavorsForImage('instance_snapshot');
|
||||
};
|
||||
|
||||
var volumeChangeCallback = function() {
|
||||
scope.updateFlavorUsage();
|
||||
};
|
||||
|
||||
$('#id_flavor').on('keyup change', eventCallback);
|
||||
$('#id_count').on('input', eventCallback);
|
||||
$('#id_image_id').on('change', imageChangeCallback);
|
||||
$('#id_instance_snapshot_id').on('change', snapshotChangeCallback);
|
||||
$('#id_source_type').on('change', volumeChangeCallback);
|
||||
$('#id_volume_snapshot_id').on('change', volumeChangeCallback);
|
||||
$('#id_image_id').on('change', volumeChangeCallback);
|
||||
$('#id_volume_size').on('keyup change', volumeChangeCallback);
|
||||
}
|
||||
|
||||
$(this.user_value_form_inputs).each(function(index, element) {
|
||||
|
Loading…
Reference in New Issue
Block a user