Replace "Terminate Instance" with "Delete Instance"

"Delete" is being used almost everywhere in OpenStack Dashboard
except the instance panel. Using "Delete" looks more consistent.
In addition, "Delete" tells non-native English speakers that
deleted instances will be no longer usable again compared to
"Terminate".

DocImpact
Closes-Bug: #1502773
Change-Id: Idccaf3c45566f20f11d02ada64c1d3934a6f3002
This commit is contained in:
Akihiro Motoki 2015-10-06 20:24:22 +09:00
parent 2432283fbc
commit 5fc26b0a11
21 changed files with 104 additions and 101 deletions

View File

@ -182,13 +182,13 @@ horizon.addInitFunction(horizon.instances.init = function () {
elements_list = "#id_instance_snapshot_id"; elements_list = "#id_instance_snapshot_id";
break; break;
case "volume_id": case "volume_id":
elements_list = "#id_volume_id, #id_device_name, #id_delete_on_terminate"; elements_list = "#id_volume_id, #id_device_name, #id_vol_delete_on_instance_delete";
break; break;
case "volume_image_id": case "volume_image_id":
elements_list = "#id_image_id, #id_volume_size, #id_device_name, #id_delete_on_terminate"; elements_list = "#id_image_id, #id_volume_size, #id_device_name, #id_vol_delete_on_instance_delete";
break; break;
case "volume_snapshot_id": case "volume_snapshot_id":
elements_list = "#id_volume_snapshot_id, #id_device_name, #id_delete_on_terminate"; elements_list = "#id_volume_snapshot_id, #id_device_name, #id_vol_delete_on_instance_delete";
break; break;
} }
var elements_list_group = $(elements_list).closest(".form-group"); var elements_list_group = $(elements_list).closest(".form-group");

View File

@ -986,7 +986,7 @@ horizon.network_topology = {
table2:portTmpl table2:portTmpl
}); });
} else if (d instanceof Server) { } else if (d instanceof Server) {
htmlData.delete_label = gettext('Terminate Instance'); htmlData.delete_label = gettext('Delete Instance');
htmlData.view_details_label = gettext('View Instance Details'); htmlData.view_details_label = gettext('View Instance Details');
htmlData.console_id = d.id; htmlData.console_id = d.id;
htmlData.ips = d.ip_addresses; htmlData.ips = d.ip_addresses;

View File

@ -29,25 +29,25 @@ from openstack_dashboard.contrib.trove.content.databases import db_capability
ACTIVE_STATES = ("ACTIVE",) ACTIVE_STATES = ("ACTIVE",)
class TerminateCluster(tables.BatchAction): class DeleteCluster(tables.BatchAction):
name = "terminate" name = "delete"
icon = "remove" icon = "remove"
classes = ('btn-danger',) classes = ('btn-danger',)
help_text = _("Terminated cluster is not recoverable.") help_text = _("Deleted cluster is not recoverable.")
@staticmethod @staticmethod
def action_present(count): def action_present(count):
return ungettext_lazy( return ungettext_lazy(
u"Terminate Cluster", u"Delete Cluster",
u"Terminate Clusters", u"Delete Clusters",
count count
) )
@staticmethod @staticmethod
def action_past(count): def action_past(count):
return ungettext_lazy( return ungettext_lazy(
u"Scheduled termination of Cluster", u"Scheduled deletion of Cluster",
u"Scheduled termination of Clusters", u"Scheduled deletion of Clusters",
count count
) )
@ -159,8 +159,8 @@ class ClustersTable(tables.DataTable):
verbose_name = _("Clusters") verbose_name = _("Clusters")
status_columns = ["task"] status_columns = ["task"]
row_class = UpdateRow row_class = UpdateRow
table_actions = (LaunchLink, TerminateCluster) table_actions = (LaunchLink, DeleteCluster)
row_actions = (AddShard, ResetPassword, TerminateCluster) row_actions = (AddShard, ResetPassword, DeleteCluster)
def get_instance_size(instance): def get_instance_size(instance):

View File

@ -31,26 +31,26 @@ from openstack_dashboard.contrib.trove.content.database_backups \
ACTIVE_STATES = ("ACTIVE",) ACTIVE_STATES = ("ACTIVE",)
class TerminateInstance(tables.BatchAction): class DeleteInstance(tables.BatchAction):
help_text = _("Terminated instances are not recoverable.") help_text = _("Deleted instances are not recoverable.")
@staticmethod @staticmethod
def action_present(count): def action_present(count):
return ungettext_lazy( return ungettext_lazy(
u"Terminate Instance", u"Delete Instance",
u"Terminate Instances", u"Delete Instances",
count count
) )
@staticmethod @staticmethod
def action_past(count): def action_past(count):
return ungettext_lazy( return ungettext_lazy(
u"Scheduled termination of Instance", u"Scheduled deletion of Instance",
u"Scheduled termination of Instances", u"Scheduled deletion of Instances",
count count
) )
name = "terminate" name = "delete"
classes = ("btn-danger", ) classes = ("btn-danger", )
icon = "remove" icon = "remove"
@ -340,13 +340,13 @@ class InstancesTable(tables.DataTable):
verbose_name = _("Instances") verbose_name = _("Instances")
status_columns = ["status"] status_columns = ["status"]
row_class = UpdateRow row_class = UpdateRow
table_actions = (LaunchLink, TerminateInstance) table_actions = (LaunchLink, DeleteInstance)
row_actions = (CreateBackup, row_actions = (CreateBackup,
ResizeVolume, ResizeVolume,
ResizeInstance, ResizeInstance,
RestartInstance, RestartInstance,
DetachReplica, DetachReplica,
TerminateInstance) DeleteInstance)
class UsersTable(tables.DataTable): class UsersTable(tables.DataTable):

View File

@ -171,7 +171,7 @@ class AdminInstancesTable(tables.DataTable):
name = "instances" name = "instances"
verbose_name = _("Instances") verbose_name = _("Instances")
status_columns = ["status", "task"] status_columns = ["status", "task"]
table_actions = (project_tables.TerminateInstance, table_actions = (project_tables.DeleteInstance,
AdminInstanceFilterAction) AdminInstanceFilterAction)
row_class = AdminUpdateRow row_class = AdminUpdateRow
row_actions = (project_tables.ConfirmResize, row_actions = (project_tables.ConfirmResize,
@ -187,4 +187,4 @@ class AdminInstancesTable(tables.DataTable):
LiveMigrateInstance, LiveMigrateInstance,
project_tables.SoftRebootInstance, project_tables.SoftRebootInstance,
project_tables.RebootInstance, project_tables.RebootInstance,
project_tables.TerminateInstance) project_tables.DeleteInstance)

View File

@ -81,31 +81,31 @@ def is_deleting(instance):
return task_state.lower() == "deleting" return task_state.lower() == "deleting"
class TerminateInstance(policy.PolicyTargetMixin, tables.BatchAction): class DeleteInstance(policy.PolicyTargetMixin, tables.BatchAction):
name = "terminate" name = "delete"
classes = ("btn-danger",) classes = ("btn-danger",)
icon = "remove" icon = "remove"
policy_rules = (("compute", "compute:delete"),) policy_rules = (("compute", "compute:delete"),)
help_text = _("Terminated instances are not recoverable.") help_text = _("Deleted instances are not recoverable.")
@staticmethod @staticmethod
def action_present(count): def action_present(count):
return ungettext_lazy( return ungettext_lazy(
u"Terminate Instance", u"Delete Instance",
u"Terminate Instances", u"Delete Instances",
count count
) )
@staticmethod @staticmethod
def action_past(count): def action_past(count):
return ungettext_lazy( return ungettext_lazy(
u"Scheduled termination of Instance", u"Scheduled deletion of Instance",
u"Scheduled termination of Instances", u"Scheduled deletion of Instances",
count count
) )
def allowed(self, request, instance=None): def allowed(self, request, instance=None):
"""Allow terminate action if instance not currently being deleted.""" """Allow delete action if instance not currently being deleted."""
return not is_deleting(instance) return not is_deleting(instance)
def action(self, request, obj_id): def action(self, request, obj_id):
@ -1174,7 +1174,7 @@ class InstancesTable(tables.DataTable):
launch_actions = (LaunchLink,) + launch_actions launch_actions = (LaunchLink,) + launch_actions
if getattr(settings, 'LAUNCH_INSTANCE_NG_ENABLED', False): if getattr(settings, 'LAUNCH_INSTANCE_NG_ENABLED', False):
launch_actions = (LaunchLinkNG,) + launch_actions launch_actions = (LaunchLinkNG,) + launch_actions
table_actions = launch_actions + (TerminateInstance, table_actions = launch_actions + (DeleteInstance,
InstancesFilterAction) InstancesFilterAction)
row_actions = (StartInstance, ConfirmResize, RevertResize, row_actions = (StartInstance, ConfirmResize, RevertResize,
CreateSnapshot, SimpleAssociateIP, AssociateIP, CreateSnapshot, SimpleAssociateIP, AssociateIP,
@ -1184,4 +1184,4 @@ class InstancesTable(tables.DataTable):
ConsoleLink, LogLink, TogglePause, ToggleSuspend, ConsoleLink, LogLink, TogglePause, ToggleSuspend,
ToggleShelve, ResizeLink, LockInstance, UnlockInstance, ToggleShelve, ResizeLink, LockInstance, UnlockInstance,
SoftRebootInstance, RebootInstance, SoftRebootInstance, RebootInstance,
StopInstance, RebuildInstance, TerminateInstance) StopInstance, RebuildInstance, DeleteInstance)

View File

@ -10,7 +10,7 @@
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
$(function () { $(function () {
var $flavor = $("#flavor_details_{{ id }}"); var $flavor = $("#flavor_details_{{ id }}");
// NOTE(tsufiev): check this in case this template is used in network topology -> terminate instance // NOTE(tsufiev): check this in case this template is used in network topology -> delete instance
if ( $flavor.popover ) { if ( $flavor.popover ) {
$flavor.popover({html:true}); $flavor.popover({html:true});
} }

View File

@ -242,7 +242,7 @@ class InstanceTests(helpers.TestCase):
'server_delete',), 'server_delete',),
api.glance: ('image_list_detailed',), api.glance: ('image_list_detailed',),
api.network: ('servers_update_addresses',)}) api.network: ('servers_update_addresses',)})
def test_terminate_instance(self): def test_delete_instance(self):
servers = self.servers.list() servers = self.servers.list()
server = servers[0] server = servers[0]
@ -256,7 +256,7 @@ class InstanceTests(helpers.TestCase):
api.nova.server_delete(IsA(http.HttpRequest), server.id) api.nova.server_delete(IsA(http.HttpRequest), server.id)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'action': 'instances__terminate__%s' % server.id} formData = {'action': 'instances__delete__%s' % server.id}
res = self.client.post(INDEX_URL, formData) res = self.client.post(INDEX_URL, formData)
self.assertRedirectsNoFollow(res, INDEX_URL) self.assertRedirectsNoFollow(res, INDEX_URL)
@ -266,7 +266,7 @@ class InstanceTests(helpers.TestCase):
'server_delete',), 'server_delete',),
api.glance: ('image_list_detailed',), api.glance: ('image_list_detailed',),
api.network: ('servers_update_addresses',)}) api.network: ('servers_update_addresses',)})
def test_terminate_instance_exception(self): def test_delete_instance_exception(self):
servers = self.servers.list() servers = self.servers.list()
server = servers[0] server = servers[0]
@ -282,7 +282,7 @@ class InstanceTests(helpers.TestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'action': 'instances__terminate__%s' % server.id} formData = {'action': 'instances__delete__%s' % server.id}
res = self.client.post(INDEX_URL, formData) res = self.client.post(INDEX_URL, formData)
self.assertRedirectsNoFollow(res, INDEX_URL) self.assertRedirectsNoFollow(res, INDEX_URL)
@ -4384,7 +4384,7 @@ class InstanceTests(helpers.TestCase):
'server_delete',), 'server_delete',),
api.glance: ('image_list_detailed',), api.glance: ('image_list_detailed',),
api.network: ('servers_update_addresses',)}) api.network: ('servers_update_addresses',)})
def test_terminate_instance_with_pagination(self): def test_delete_instance_with_pagination(self):
"""Instance should be deleted from """Instance should be deleted from
the next page. the next page.
""" """
@ -4408,7 +4408,7 @@ class InstanceTests(helpers.TestCase):
servers[page_size - 1].id]) servers[page_size - 1].id])
next_page_url = "?".join([reverse('horizon:project:instances:index'), next_page_url = "?".join([reverse('horizon:project:instances:index'),
params]) params])
formData = {'action': 'instances__terminate__%s' % server.id} formData = {'action': 'instances__delete__%s' % server.id}
res = self.client.post(next_page_url, formData) res = self.client.post(next_page_url, formData)
self.assertRedirectsNoFollow(res, next_page_url) self.assertRedirectsNoFollow(res, next_page_url)

View File

@ -128,11 +128,11 @@ class SetInstanceDetailsAction(workflows.Action):
"system choose a device name " "system choose a device name "
"for you.")) "for you."))
delete_on_terminate = forms.BooleanField(label=_("Delete on Terminate"), vol_delete_on_instance_delete = forms.BooleanField(
initial=False, label=_("Delete Volume on Instance Delete"),
required=False, initial=False,
help_text=_("Delete volume on " required=False,
"instance terminate")) help_text=_("Delete volume when the instance is deleted"))
class Meta(object): class Meta(object):
name = _("Details") name = _("Details")
@ -507,7 +507,7 @@ class SetInstanceDetails(workflows.Step):
contributes = ("source_type", "source_id", contributes = ("source_type", "source_id",
"availability_zone", "name", "count", "flavor", "availability_zone", "name", "count", "flavor",
"device_name", # Can be None for an image. "device_name", # Can be None for an image.
"delete_on_terminate") "vol_delete_on_instance_delete")
def prepare_action_context(self, request, context): def prepare_action_context(self, request, context):
if 'source_type' in context and 'source_id' in context: if 'source_type' in context and 'source_id' in context:
@ -884,17 +884,18 @@ class LaunchInstance(workflows.Workflow):
'source_type': dev_source_type_mapping[source_type], 'source_type': dev_source_type_mapping[source_type],
'destination_type': 'volume', 'destination_type': 'volume',
'delete_on_termination': 'delete_on_termination':
bool(context['delete_on_terminate']), bool(context['vol_delete_on_instance_delete']),
'uuid': volume_source_id, 'uuid': volume_source_id,
'boot_index': '0', 'boot_index': '0',
'volume_size': context['volume_size'] 'volume_size': context['volume_size']
} }
] ]
else: else:
dev_mapping_1 = {context['device_name']: '%s::%s' % dev_mapping_1 = {
(context['source_id'], context['device_name']: '%s::%s' %
bool(context['delete_on_terminate'])) (context['source_id'],
} bool(context['vol_delete_on_instance_delete']))
}
except Exception: except Exception:
msg = _('Unable to retrieve extensions information') msg = _('Unable to retrieve extensions information')
exceptions.handle(request, msg) exceptions.handle(request, msg)
@ -906,7 +907,7 @@ class LaunchInstance(workflows.Workflow):
'source_type': 'image', 'source_type': 'image',
'destination_type': 'volume', 'destination_type': 'volume',
'delete_on_termination': 'delete_on_termination':
bool(context['delete_on_terminate']), bool(context['vol_delete_on_instance_delete']),
'uuid': context['source_id'], 'uuid': context['source_id'],
'boot_index': '0', 'boot_index': '0',
'volume_size': context['volume_size'] 'volume_size': context['volume_size']

View File

@ -22,5 +22,5 @@ class InstancesTable(tables.InstancesTable):
name = "instances" name = "instances"
verbose_name = _("Instances") verbose_name = _("Instances")
row_actions = ( row_actions = (
tables.TerminateInstance, tables.DeleteInstance,
) )

View File

@ -160,7 +160,7 @@
vol_create: false, vol_create: false,
// May be null // May be null
vol_device_name: 'vda', vol_device_name: 'vda',
vol_delete_on_terminate: false, vol_delete_on_instance_delete: false,
vol_size: 1 vol_size: 1
}; };
} }
@ -472,7 +472,7 @@
delete finalSpec.source_type; delete finalSpec.source_type;
delete finalSpec.vol_create; delete finalSpec.vol_create;
delete finalSpec.vol_device_name; delete finalSpec.vol_device_name;
delete finalSpec.vol_delete_on_terminate; delete finalSpec.vol_delete_on_instance_delete;
delete finalSpec.vol_size; delete finalSpec.vol_size;
} }
@ -486,7 +486,7 @@
'device_name': deviceName, 'device_name': deviceName,
'source_type': SOURCE_TYPE_IMAGE, 'source_type': SOURCE_TYPE_IMAGE,
'destination_type': SOURCE_TYPE_VOLUME, 'destination_type': SOURCE_TYPE_VOLUME,
'delete_on_termination': finalSpec.vol_delete_on_terminate, 'delete_on_termination': finalSpec.vol_delete_on_instance_delete,
'uuid': finalSpec.source_id, 'uuid': finalSpec.source_id,
'boot_index': '0', 'boot_index': '0',
'volume_size': finalSpec.vol_size 'volume_size': finalSpec.vol_size
@ -503,7 +503,7 @@
':', ':',
sourceType, sourceType,
'::', '::',
finalSpec.vol_delete_on_terminate finalSpec.vol_delete_on_instance_delete
].join(''); ].join('');
// Source ID must be empty for API // Source ID must be empty for API

View File

@ -373,7 +373,7 @@
it('sets volume options appropriately', function() { it('sets volume options appropriately', function() {
expect(model.newInstanceSpec.vol_create).toBe(false); expect(model.newInstanceSpec.vol_create).toBe(false);
expect(model.newInstanceSpec.vol_device_name).toBe('vda'); expect(model.newInstanceSpec.vol_device_name).toBe('vda');
expect(model.newInstanceSpec.vol_delete_on_terminate).toBe(false); expect(model.newInstanceSpec.vol_delete_on_instance_delete).toBe(false);
expect(model.newInstanceSpec.vol_size).toBe(1); expect(model.newInstanceSpec.vol_size).toBe(1);
}); });
@ -391,7 +391,7 @@
model.newInstanceSpec.security_groups = [ { id: 'adminId', name: 'admin' }, model.newInstanceSpec.security_groups = [ { id: 'adminId', name: 'admin' },
{ id: 'demoId', name: 'demo' } ]; { id: 'demoId', name: 'demo' } ];
model.newInstanceSpec.vol_create = true; model.newInstanceSpec.vol_create = true;
model.newInstanceSpec.vol_delete_on_terminate = true; model.newInstanceSpec.vol_delete_on_instance_delete = true;
model.newInstanceSpec.vol_device_name = "volTestName"; model.newInstanceSpec.vol_device_name = "volTestName";
model.newInstanceSpec.vol_size = 10; model.newInstanceSpec.vol_size = 10;
}); });
@ -442,7 +442,7 @@
it('should handle source type of "volume"', function() { it('should handle source type of "volume"', function() {
model.newInstanceSpec.source_type.type = 'volume'; model.newInstanceSpec.source_type.type = 'volume';
model.newInstanceSpec.source[0].id = 'imAnID'; model.newInstanceSpec.source[0].id = 'imAnID';
model.newInstanceSpec.vol_delete_on_terminate = 'yep'; model.newInstanceSpec.vol_delete_on_instance_delete = 'yep';
var finalSpec = model.createInstance(); var finalSpec = model.createInstance();
expect(finalSpec.block_device_mapping.volTestName) expect(finalSpec.block_device_mapping.volTestName)
@ -461,7 +461,7 @@
it('should handle source type of "volume_snapshot"', function() { it('should handle source type of "volume_snapshot"', function() {
model.newInstanceSpec.source_type.type = 'volume_snapshot'; model.newInstanceSpec.source_type.type = 'volume_snapshot';
model.newInstanceSpec.source[0].id = 'imAnID'; model.newInstanceSpec.source[0].id = 'imAnID';
model.newInstanceSpec.vol_delete_on_terminate = 'yep'; model.newInstanceSpec.vol_delete_on_instance_delete = 'yep';
var finalSpec = model.createInstance(); var finalSpec = model.createInstance();
expect(finalSpec.block_device_mapping.volTestName) expect(finalSpec.block_device_mapping.volTestName)

View File

@ -240,7 +240,7 @@
function updateBootSourceSelection(selectedSource) { function updateBootSourceSelection(selectedSource) {
ctrl.currentBootSource = selectedSource; ctrl.currentBootSource = selectedSource;
$scope.model.newInstanceSpec.vol_create = false; $scope.model.newInstanceSpec.vol_create = false;
$scope.model.newInstanceSpec.vol_delete_on_terminate = false; $scope.model.newInstanceSpec.vol_delete_on_instance_delete = false;
changeBootSource(selectedSource); changeBootSource(selectedSource);
validateBootSourceType(); validateBootSourceType();
} }

View File

@ -137,7 +137,7 @@
expect(ctrl.currentBootSource).toEqual('image'); expect(ctrl.currentBootSource).toEqual('image');
expect(scope.model.newInstanceSpec.vol_create).toBe(false); expect(scope.model.newInstanceSpec.vol_create).toBe(false);
expect(scope.model.newInstanceSpec.vol_delete_on_terminate).toBe(false); expect(scope.model.newInstanceSpec.vol_delete_on_instance_delete).toBe(false);
// check table data // check table data
expect(ctrl.tableData).toBeDefined(); expect(ctrl.tableData).toBeDefined();

View File

@ -6,8 +6,8 @@
<p translate><li><b>Image</b>: This option uses an image to boot the instance.</li></p> <p translate><li><b>Image</b>: This option uses an image to boot the instance.</li></p>
<p translate><li><b>Instance Snapshot</b>: This option uses an instance snapshot to boot the instance.</li></p> <p translate><li><b>Instance Snapshot</b>: This option uses an instance snapshot to boot the instance.</li></p>
<p translate>If you want to create an instance that uses persistent storage, meaning the instance data is saved when the instance is deleted, then select one of the following boot options:</p> <p translate>If you want to create an instance that uses persistent storage, meaning the instance data is saved when the instance is deleted, then select one of the following boot options:</p>
<p translate><li><b>Image (with Create New Volume checked)</b>: This options uses an image to boot the instance, and creates a new volume to persist instance data. You can specify volume size and whether to delete the volume on termination of the instance.</li></p> <p translate><li><b>Image (with Create New Volume checked)</b>: This options uses an image to boot the instance, and creates a new volume to persist instance data. You can specify volume size and whether to delete the volume on deletion of the instance.</li></p>
<p translate><li><b>Volume</b>: This option uses a volume that already exists. It does not create a new volume. You can choose to delete the volume on termination of the instance. <em>Note: when selecting Volume, you can only launch one instance.</em></li></p> <p translate><li><b>Volume</b>: This option uses a volume that already exists. It does not create a new volume. You can choose to delete the volume on deletion of the instance. <em>Note: when selecting Volume, you can only launch one instance.</em></li></p>
<p translate><li><b>Volume Snapshot</b>: This option uses a volume snapshot to boot the instance, and creates a new volume to persist instance data. You can choose to delete the volume on termination of the instance.</li></p> <p translate><li><b>Volume Snapshot</b>: This option uses a volume snapshot to boot the instance, and creates a new volume to persist instance data. You can choose to delete the volume on deletion of the instance.</li></p>
</div> </div>

View File

@ -77,12 +77,12 @@
<div class="col-xs-12 col-sm-4" ng-if="model.newInstanceSpec.vol_create == true"> <div class="col-xs-12 col-sm-4" ng-if="model.newInstanceSpec.vol_create == true">
<div class="form-group delete-volume"> <div class="form-group delete-volume">
<label translate class="on-top">Delete Volume on Terminate</label> <label translate class="on-top">Delete Volume on Instance Delete</label>
<div class="form-field"> <div class="form-field">
<div class="btn-group"> <div class="btn-group">
<label class="btn btn-toggle" <label class="btn btn-toggle"
ng-repeat="option in ctrl.toggleButtonOptions" ng-repeat="option in ctrl.toggleButtonOptions"
ng-model="model.newInstanceSpec.vol_delete_on_terminate" ng-model="model.newInstanceSpec.vol_delete_on_instance_delete"
btn-radio="option.value">{$ ::option.label $}</label> btn-radio="option.value">{$ ::option.label $}</label>
</div> </div>
</div> </div>
@ -96,12 +96,12 @@
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
<div class="form-group delete-volume"> <div class="form-group delete-volume">
<label translate class="on-top">Delete Volume on Terminate</label> <label translate class="on-top">Delete Volume on Instance Delete</label>
<div class="form-field"> <div class="form-field">
<div class="btn-group"> <div class="btn-group">
<label class="btn btn-toggle" <label class="btn btn-toggle"
ng-repeat="option in ctrl.toggleButtonOptions" ng-repeat="option in ctrl.toggleButtonOptions"
ng-model="model.newInstanceSpec.vol_delete_on_terminate" ng-model="model.newInstanceSpec.vol_delete_on_instance_delete"
btn-radio="option.value">{$ ::option.label $}</label> btn-radio="option.value">{$ ::option.label $}</label>
</div> </div>
</div> </div>

View File

@ -545,7 +545,7 @@ div.input input[type="checkbox"] {
width: 25px; width: 25px;
} }
tr.terminated { tr.deleted {
color: #999999; color: #999999;
} }

View File

@ -25,13 +25,13 @@ class InstancesPage(basepage.BaseNavigationPage):
DEFAULT_VOLUME_NAME = None DEFAULT_VOLUME_NAME = None
DEFAULT_SNAPSHOT_NAME = None DEFAULT_SNAPSHOT_NAME = None
DEFAULT_VOLUME_SNAPSHOT_NAME = None DEFAULT_VOLUME_SNAPSHOT_NAME = None
DEFAULT_DELETE_ON_TERMINATE = False DEFAULT_VOL_DELETE_ON_INSTANCE_DELETE = False
DEFAULT_SECURITY_GROUP = True DEFAULT_SECURITY_GROUP = True
_instances_table_locator = (by.By.CSS_SELECTOR, 'table#instances') _instances_table_locator = (by.By.CSS_SELECTOR, 'table#instances')
INSTANCES_TABLE_NAME = "instances" INSTANCES_TABLE_NAME = "instances"
INSTANCES_TABLE_ACTIONS = ("launch_ng", "launch", "terminate", INSTANCES_TABLE_ACTIONS = ("launch_ng", "launch", "delete",
('start', 'stop', "reboot")) ('start', 'stop', "reboot"))
INSTANCES_TABLE_NAME_COLUMN_INDEX = 0 INSTANCES_TABLE_NAME_COLUMN_INDEX = 0
INSTANCES_TABLE_STATUS_COLUMN_INDEX = 5 INSTANCES_TABLE_STATUS_COLUMN_INDEX = 5
@ -41,14 +41,14 @@ class InstancesPage(basepage.BaseNavigationPage):
"associate_floating_ip", "disassociate_floating_ip", "associate_floating_ip", "disassociate_floating_ip",
"edit_instance", "edit_security_groups", "console", "edit_instance", "edit_security_groups", "console",
"view_log", "pause", "suspend", "resize", "lock", "unlock", "view_log", "pause", "suspend", "resize", "lock", "unlock",
"soft_reboot", "hard_reboot", "shutoff", "rebuild", "terminate") "soft_reboot", "hard_reboot", "shutoff", "rebuild", "delete")
} }
CREATE_INSTANCE_FORM_FIELDS = (( CREATE_INSTANCE_FORM_FIELDS = ((
"availability_zone", "name", "flavor", "availability_zone", "name", "flavor",
"count", "source_type", "instance_snapshot_id", "count", "source_type", "instance_snapshot_id",
"volume_id", "volume_snapshot_id", "image_id", "volume_size", "volume_id", "volume_snapshot_id", "image_id", "volume_size",
"delete_on_terminate"), "vol_delete_on_instance_delete"),
("keypair", "groups"), ("keypair", "groups"),
("script_source", "script_upload", "script_data"), ("script_source", "script_upload", "script_data"),
("disk_config", "config_drive") ("disk_config", "config_drive")
@ -88,14 +88,16 @@ class InstancesPage(basepage.BaseNavigationPage):
def is_instance_present(self, name): def is_instance_present(self, name):
return bool(self._get_row_with_instance_name(name)) return bool(self._get_row_with_instance_name(name))
def create_instance(self, instance_name, def create_instance(
available_zone=None, self, instance_name,
instance_count=DEFAULT_COUNT, available_zone=None,
flavor=DEFAULT_FLAVOR, instance_count=DEFAULT_COUNT,
boot_source=DEFAULT_BOOT_SOURCE, flavor=DEFAULT_FLAVOR,
source_name=None, boot_source=DEFAULT_BOOT_SOURCE,
device_size=None, source_name=None,
delete_on_terminate=DEFAULT_DELETE_ON_TERMINATE): device_size=None,
vol_delete_on_instance_delete=DEFAULT_VOL_DELETE_ON_INSTANCE_DELETE
):
if not available_zone: if not available_zone:
available_zone = self.conf.launch_instances.available_zone available_zone = self.conf.launch_instances.available_zone
self.instances_table.launch.click() self.instances_table.launch.click()
@ -112,19 +114,19 @@ class InstancesPage(basepage.BaseNavigationPage):
boot_source[0].text = source_name boot_source[0].text = source_name
if device_size: if device_size:
instance.volume_size.value = device_size instance.volume_size.value = device_size
if delete_on_terminate: if vol_delete_on_instance_delete:
instance.delete_on_terminate.mark() instance.vol_delete_on_instance_delete.mark()
instance.submit.click() instance.submit.click()
self.wait_till_popups_disappear() self.wait_till_popups_disappear()
def terminate_instance(self, name): def delete_instance(self, name):
row = self._get_row_with_instance_name(name) row = self._get_row_with_instance_name(name)
row.mark() row.mark()
self.instances_table.terminate.click() self.instances_table.delete.click()
self.confirm_delete_instances_form.submit.click() self.confirm_delete_instances_form.submit.click()
self.wait_till_popups_disappear() self.wait_till_popups_disappear()
def is_instance_terminated(self, name): def is_instance_deleted(self, name):
try: try:
row = self._get_row_with_instance_name(name) row = self._get_row_with_instance_name(name)
self._wait_till_element_disappears(row) self._wait_till_element_disappears(row)

View File

@ -17,12 +17,12 @@ INSTANCES_NAME = helpers.gen_random_resource_name('instance',
class TestInstances(helpers.AdminTestCase): class TestInstances(helpers.AdminTestCase):
"""This is a basic scenario to test: """This is a basic scenario to test:
* Create Instance and Terminate Instance * Create Instance and Delete Instance
""" """
def test_create_terminate_instance(self): def test_create_delete_instance(self):
instances_page = self.home_pg.go_to_compute_instancespage() instances_page = self.home_pg.go_to_compute_instancespage()
instances_page.create_instance(INSTANCES_NAME) instances_page.create_instance(INSTANCES_NAME)
self.assertTrue(instances_page.is_instance_active(INSTANCES_NAME)) self.assertTrue(instances_page.is_instance_active(INSTANCES_NAME))
instances_page.terminate_instance(INSTANCES_NAME) instances_page.delete_instance(INSTANCES_NAME)
self.assertTrue(instances_page.is_instance_terminated(INSTANCES_NAME)) self.assertTrue(instances_page.is_instance_deleted(INSTANCES_NAME))

View File

@ -26,7 +26,7 @@ from openstack_dashboard.usage import quotas
class BaseUsage(object): class BaseUsage(object):
show_terminated = False show_deleted = False
def __init__(self, request, project_id=None): def __init__(self, request, project_id=None):
self.project_id = project_id or request.user.tenant_id self.project_id = project_id or request.user.tenant_id
@ -248,7 +248,7 @@ class BaseUsage(object):
class GlobalUsage(BaseUsage): class GlobalUsage(BaseUsage):
show_terminated = True show_deleted = True
def get_usage_list(self, start, end): def get_usage_list(self, start, end):
return api.nova.usage_list(self.request, start, end) return api.nova.usage_list(self.request, start, end)
@ -259,10 +259,10 @@ class ProjectUsage(BaseUsage):
'hours', 'local_gb') 'hours', 'local_gb')
def get_usage_list(self, start, end): def get_usage_list(self, start, end):
show_terminated = self.request.GET.get('show_terminated', show_deleted = self.request.GET.get('show_deleted',
self.show_terminated) self.show_deleted)
instances = [] instances = []
terminated_instances = [] deleted_instances = []
usage = api.nova.usage_get(self.request, self.project_id, start, end) usage = api.nova.usage_get(self.request, self.project_id, start, end)
# Attribute may not exist if there are no instances # Attribute may not exist if there are no instances
if hasattr(usage, 'server_usages'): if hasattr(usage, 'server_usages'):
@ -273,8 +273,8 @@ class ProjectUsage(BaseUsage):
server_uptime = server_usage['uptime'] server_uptime = server_usage['uptime']
total_uptime = now - datetime.timedelta(seconds=server_uptime) total_uptime = now - datetime.timedelta(seconds=server_uptime)
server_usage['uptime_at'] = total_uptime server_usage['uptime_at'] = total_uptime
if server_usage['ended_at'] and not show_terminated: if server_usage['ended_at'] and not show_deleted:
terminated_instances.append(server_usage) deleted_instances.append(server_usage)
else: else:
instances.append(server_usage) instances.append(server_usage)
usage.server_usages = instances usage.server_usages = instances

View File

@ -20,7 +20,7 @@ from openstack_dashboard.usage import base
class UsageView(tables.DataTableView): class UsageView(tables.DataTableView):
usage_class = None usage_class = None
show_terminated = True show_deleted = True
csv_template_name = None csv_template_name = None
page_title = _("Overview") page_title = _("Overview")