From 39daba1e9d281cf67be31dceae10a9ad01952595 Mon Sep 17 00:00:00 2001 From: Ali Adil Date: Mon, 18 Jul 2016 21:09:05 +0000 Subject: [PATCH] Add command to delete BUILD instances and clusters Sometimes an instance/cluster can be stuck in BUILD state forever. Attempting to delete the instance in this state is currently not allowed. Add force-delete and reset-status command. Reset-status will reset the status to ERROR, letting the instance/cluster be deleted. Force-delete will combine functionality of reset-status and delete. Change-Id: I957b4be5030e493e0eb8c6b6855d41b942b2823c Partial-Bug: #1579141 --- .../notes/force_delete-2d6bb5f99fe821c5.yaml | 6 ++++ troveclient/tests/test_v1_shell.py | 16 +++++++++ troveclient/v1/clusters.py | 13 +++++++ troveclient/v1/instances.py | 21 +++++++++++ troveclient/v1/shell.py | 36 +++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 releasenotes/notes/force_delete-2d6bb5f99fe821c5.yaml diff --git a/releasenotes/notes/force_delete-2d6bb5f99fe821c5.yaml b/releasenotes/notes/force_delete-2d6bb5f99fe821c5.yaml new file mode 100644 index 00000000..3b5c89fb --- /dev/null +++ b/releasenotes/notes/force_delete-2d6bb5f99fe821c5.yaml @@ -0,0 +1,6 @@ +features: + - The reset-status command will set the task and status + of an instance to ERROR after which it can be deleted. + - The force-delete command will allow the deletion of + an instance even if the instance is stuck in BUILD + state. diff --git a/troveclient/tests/test_v1_shell.py b/troveclient/tests/test_v1_shell.py index 405ed66b..2d7ab132 100644 --- a/troveclient/tests/test_v1_shell.py +++ b/troveclient/tests/test_v1_shell.py @@ -175,10 +175,18 @@ class ShellTest(utils.TestCase): self.run_command('show 1234') self.assert_called('GET', '/instances/1234') + def test_reset_status(self): + self.run_command('reset-status 1234') + self.assert_called('POST', '/instances/1234/action') + def test_instance_delete(self): self.run_command('delete 1234') self.assert_called('DELETE', '/instances/1234') + def test_instance_force_delete(self): + self.run_command('force-delete 1234') + self.assert_called('DELETE', '/instances/1234') + def test_instance_update(self): self.run_command('update 1234') self.assert_called('PATCH', '/instances/1234') @@ -250,10 +258,18 @@ class ShellTest(utils.TestCase): self.run_command('cluster-instances cls-1234') self.assert_called('GET', '/clusters/cls-1234') + def test_cluster_reset_status(self): + self.run_command('cluster-reset-status cls-1234') + self.assert_called('POST', '/clusters/cls-1234') + def test_cluster_delete(self): self.run_command('cluster-delete cls-1234') self.assert_called('DELETE', '/clusters/cls-1234') + def test_cluster_force_delete(self): + self.run_command('cluster-force-delete cls-1234') + self.assert_called('DELETE', '/clusters/cls-1234') + def test_boot(self): self.run_command('create test-member-1 1 --size 1 --volume_type lvm') self.assert_called_anytime( diff --git a/troveclient/v1/clusters.py b/troveclient/v1/clusters.py index 6dc44dfe..451bfe8e 100644 --- a/troveclient/v1/clusters.py +++ b/troveclient/v1/clusters.py @@ -26,6 +26,11 @@ class Cluster(base.Resource): """Delete the cluster.""" self.manager.delete(self) + def force_delete(self): + """Force delete the cluster""" + self.manager.reset_status(self) + self.manager.delete(self) + class Clusters(base.ManagerWithFind): """Manage :class:`Cluster` resources.""" @@ -73,6 +78,14 @@ class Clusters(base.ManagerWithFind): resp, body = self.api.client.delete(url) common.check_for_exceptions(resp, body, url) + def reset_status(self, cluster): + """Reset the status of a cluster + + :param cluster: The cluster to reset + """ + body = {'reset-status': {}} + self._action(cluster, body) + def _action(self, cluster, body): """Perform a cluster "action" -- grow/shrink/etc.""" url = "/clusters/%s" % base.getid(cluster) diff --git a/troveclient/v1/instances.py b/troveclient/v1/instances.py index 54738c19..3e0ecd9b 100644 --- a/troveclient/v1/instances.py +++ b/troveclient/v1/instances.py @@ -41,6 +41,11 @@ class Instance(base.Resource): """Delete the instance.""" self.manager.delete(self) + def force_delete(self): + """Force delete the instance""" + self.manager.reset_status(self) + self.manager.delete(self) + def restart(self): """Restart the database instance.""" self.manager.restart(self.id) @@ -203,6 +208,22 @@ class Instances(base.ManagerWithFind): resp, body = self.api.client.delete(url) common.check_for_exceptions(resp, body, url) + def reset_status(self, instance): + """Reset the status of an instance. + + :param instance: A reference to the instance + """ + body = {'reset_status': {}} + self._action(instance, body) + + def force_delete(self, instance): + """Force delete the specified instance. + + :param instance: A reference to the instance to force delete + """ + self.reset_status(instance) + self.delete(instance) + def _action(self, instance, body): """Perform a server "action" -- reboot/rebuild/resize/etc.""" url = "/instances/%s/action" % base.getid(instance) diff --git a/troveclient/v1/shell.py b/troveclient/v1/shell.py index dde823b0..1a209beb 100644 --- a/troveclient/v1/shell.py +++ b/troveclient/v1/shell.py @@ -358,6 +358,25 @@ def do_delete(cs, args): cs.instances.delete(instance) +@utils.arg('instance', metavar='', + help='ID or name of the instance.') +@utils.service_type('database') +def do_force_delete(cs, args): + """Force delete an instance.""" + instance = _find_instance(cs, args.instance) + cs.instances.reset_status(instance) + cs.instances.delete(instance) + + +@utils.arg('instance', metavar='', + help='ID or name of the instance.') +@utils.service_type('database') +def do_reset_status(cs, args): + """Set the status to NONE.""" + instance = _find_instance(cs, args.instance) + cs.instances.reset_status(instance=instance) + + @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_delete(cs, args): @@ -366,6 +385,23 @@ def do_cluster_delete(cs, args): cs.clusters.delete(cluster) +@utils.arg('cluster', metavar='', help='ID or name of the cluster.') +@utils.service_type('database') +def do_cluster_force_delete(cs, args): + """Force delete a cluster""" + cluster = _find_cluster(cs, args.cluster) + cs.clusters.reset_status(cluster) + cs.clusters.delete(cluster) + + +@utils.arg('cluster', metavar='', help='ID or name of the cluster.') +@utils.service_type('database') +def do_cluster_reset_status(cs, args): + """Set the cluster task to NONE.""" + cluster = _find_cluster(cs, args.cluster) + cs.clusters.reset_status(cluster) + + @utils.arg('instance', metavar='', type=str,