diff options
18 files changed, 421 insertions, 3 deletions
diff --git a/releasenotes/notes/add-configuration-default-to-osc-55867236d19d83c4.yaml b/releasenotes/notes/add-configuration-default-to-osc-55867236d19d83c4.yaml new file mode 100644 index 0000000..ed58f2d --- /dev/null +++ b/releasenotes/notes/add-configuration-default-to-osc-55867236d19d83c4.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The command ``trove configuration-default`` is now available + to use in the python-openstackclient CLI as ``openstack + database configuration default`` diff --git a/releasenotes/notes/add-configuration-instances-to-osc-80a7d7b9d0c79f62.yaml b/releasenotes/notes/add-configuration-instances-to-osc-80a7d7b9d0c79f62.yaml new file mode 100644 index 0000000..4ffb250 --- /dev/null +++ b/releasenotes/notes/add-configuration-instances-to-osc-80a7d7b9d0c79f62.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The command ``trove configuration-instances`` is now available + to use in the python-openstackclient CLI as ``openstack + database configuration instances`` diff --git a/releasenotes/notes/add-detach-replica-to-osc-1fadef6220e96f35.yaml b/releasenotes/notes/add-detach-replica-to-osc-1fadef6220e96f35.yaml new file mode 100644 index 0000000..125ad87 --- /dev/null +++ b/releasenotes/notes/add-detach-replica-to-osc-1fadef6220e96f35.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The command ``trove detach-replica`` is now available + to use in the python-openstackclient CLI as ``openstack database + instance detach replica`` diff --git a/releasenotes/notes/add-eject-replica-source-to-osc-c985a70eaab3f16b.yaml b/releasenotes/notes/add-eject-replica-source-to-osc-c985a70eaab3f16b.yaml new file mode 100644 index 0000000..118d7fc --- /dev/null +++ b/releasenotes/notes/add-eject-replica-source-to-osc-c985a70eaab3f16b.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The command ``trove eject-replica-source`` is now available to use in + the python-openstackclient CLI as `` + openstack database instance eject replica source`` diff --git a/releasenotes/notes/add-execution-delete-to-osc-013b4bf00a1cb8ff.yaml b/releasenotes/notes/add-execution-delete-to-osc-013b4bf00a1cb8ff.yaml new file mode 100644 index 0000000..96ff826 --- /dev/null +++ b/releasenotes/notes/add-execution-delete-to-osc-013b4bf00a1cb8ff.yaml @@ -0,0 +1,5 @@ +--- +features: + - The command ``trove execution-delete`` is now available to use in + the python-openstackclient CLI as ``openstack database backup + execution delete`` diff --git a/releasenotes/notes/add-log-list-to-osc-4bc11aa6e20de286.yaml b/releasenotes/notes/add-log-list-to-osc-4bc11aa6e20de286.yaml new file mode 100644 index 0000000..f4c30a7 --- /dev/null +++ b/releasenotes/notes/add-log-list-to-osc-4bc11aa6e20de286.yaml @@ -0,0 +1,4 @@ +--- +features: + - The command ``trove log-list`` is now available to use in + the python-openstackclient CLI as ``openstack database log list`` @@ -32,6 +32,7 @@ openstack.cli.extension = openstack.database.v1 = database_backup_create= troveclient.osc.v1.database_backups:CreateDatabaseBackup database_backup_delete = troveclient.osc.v1.database_backups:DeleteDatabaseBackup + database_backup_execution_delete = troveclient.osc.v1.database_backups:DeleteDatabaseBackupExecution database_backup_list = troveclient.osc.v1.database_backups:ListDatabaseBackups database_backup_list_instance = troveclient.osc.v1.database_backups:ListDatabaseInstanceBackups database_backup_show = troveclient.osc.v1.database_backups:ShowDatabaseBackup @@ -48,8 +49,10 @@ openstack.database.v1 = database_cluster_upgrade = troveclient.osc.v1.database_clusters:UpgradeDatabaseCluster database_configuration_attach = troveclient.osc.v1.database_configurations:AttachDatabaseConfiguration database_configuration_create = troveclient.osc.v1.database_configurations:CreateDatabaseConfiguration + database_configuration_default = troveclient.osc.v1.database_configurations:DefaultDatabaseConfiguration database_configuration_delete = troveclient.osc.v1.database_configurations:DeleteDatabaseConfiguration database_configuration_detach = troveclient.osc.v1.database_configurations:DetachDatabaseConfiguration + database_configuration_instances = troveclient.osc.v1.database_configurations:ListDatabaseConfigurationInstances database_configuration_list = troveclient.osc.v1.database_configurations:ListDatabaseConfigurations database_configuration_parameter_list = troveclient.osc.v1.database_configurations:ListDatabaseConfigurationParameters database_configuration_parameter_show = troveclient.osc.v1.database_configurations:ShowDatabaseConfigurationParameter @@ -61,6 +64,8 @@ openstack.database.v1 = database_flavor_show = troveclient.osc.v1.database_flavors:ShowDatabaseFlavor database_instance_create = troveclient.osc.v1.database_instances:CreateDatabaseInstance database_instance_delete = troveclient.osc.v1.database_instances:DeleteDatabaseInstance + database_instance_detach_replica = troveclient.osc.v1.database_instances:DetachDatabaseInstanceReplica + database_instance_eject_replica_source = troveclient.osc.v1.database_instances:EjectDatabaseInstanceReplicaSource database_instance_force_delete = troveclient.osc.v1.database_instances:ForceDeleteDatabaseInstance database_instance_list = troveclient.osc.v1.database_instances:ListDatabaseInstances database_instance_promote_to_replica_source = troveclient.osc.v1.database_instances:PromoteDatabaseInstanceToReplicaSource @@ -72,6 +77,7 @@ openstack.database.v1 = database_instance_update = troveclient.osc.v1.database_instances:UpdateDatabaseInstance database_instance_upgrade = troveclient.osc.v1.database_instances:UpgradeDatabaseInstance database_limit_list = troveclient.osc.v1.database_limits:ListDatabaseLimits + database_log_list = troveclient.osc.v1.database_logs:ListDatabaseLogs database_quota_show = troveclient.osc.v1.database_quota:ShowDatabaseQuota database_quota_update = troveclient.osc.v1.database_quota:UpdateDatabaseQuota database_log_enable = troveclient.osc.v1.database_instances:EnableDatabaseInstanceLog diff --git a/troveclient/osc/v1/database_backups.py b/troveclient/osc/v1/database_backups.py index 8b3e973..8f2b160 100644 --- a/troveclient/osc/v1/database_backups.py +++ b/troveclient/osc/v1/database_backups.py @@ -220,3 +220,22 @@ class CreateDatabaseBackup(command.ShowOne): incremental=parsed_args.incremental) backup = set_attributes_for_print_detail(backup) return zip(*sorted(six.iteritems(backup))) + + +class DeleteDatabaseBackupExecution(command.Command): + + _description = _("Deletes an execution.") + + def get_parser(self, prog_name): + parser = super(DeleteDatabaseBackupExecution, self).get_parser( + prog_name) + parser.add_argument( + 'execution', + metavar='<execution>', + help=_('ID of the execution to delete.') + ) + return parser + + def take_action(self, parsed_args): + database_backups = self.app.client_manager.database.backups + database_backups.execution_delete(parsed_args.execution) diff --git a/troveclient/osc/v1/database_configurations.py b/troveclient/osc/v1/database_configurations.py index e4cea26..ea3f09a 100644 --- a/troveclient/osc/v1/database_configurations.py +++ b/troveclient/osc/v1/database_configurations.py @@ -306,3 +306,69 @@ class DetachDatabaseConfiguration(command.Command): instance = osc_utils.find_resource(db_instances, parsed_args.instance) db_instances.modify(instance) + + +class ListDatabaseConfigurationInstances(command.Lister): + + _description = _("Lists all instances associated " + "with a configuration group.") + columns = ['ID', 'Name'] + + def get_parser(self, prog_name): + parser = super(ListDatabaseConfigurationInstances, self).\ + get_parser(prog_name) + parser.add_argument( + 'configuration_group', + metavar='<configuration_group>', + help=_('ID or name of the configuration group.') + ) + parser.add_argument( + '--limit', + metavar='<limit>', + default=None, + type=int, + help=_('Limit the number of results displayed.') + ) + parser.add_argument( + '--marker', + metavar='<ID>', + default=None, + type=str, + help=_('Begin displaying the results for IDs greater than the ' + 'specified marker. When used with --limit, set this to ' + 'the last ID displayed in the previous run.') + ) + return parser + + def take_action(self, parsed_args): + db_configurations = self.app.client_manager.database.configurations + configuration = osc_utils.find_resource( + db_configurations, parsed_args.configuration_group) + params = db_configurations.instances(configuration, + limit=parsed_args.limit, + marker=parsed_args.marker) + instance = [osc_utils.get_item_properties(p, self.columns) + for p in params] + return self.columns, instance + + +class DefaultDatabaseConfiguration(command.ShowOne): + _description = _("Shows the default configuration of an instance.") + + def get_parser(self, prog_name): + parser = super(DefaultDatabaseConfiguration, self).get_parser( + prog_name) + parser.add_argument( + 'instance', + metavar='<instance>', + type=str, + help=_('ID or name of the instance.'), + ) + return parser + + def take_action(self, parsed_args): + db_instances = self.app.client_manager.database.instances + instance = osc_utils.find_resource(db_instances, + parsed_args.instance) + configs = db_instances.configuration(instance) + return zip(*sorted(six.iteritems(configs._info['configuration']))) diff --git a/troveclient/osc/v1/database_instances.py b/troveclient/osc/v1/database_instances.py index 8fae357..3bb6a74 100644 --- a/troveclient/osc/v1/database_instances.py +++ b/troveclient/osc/v1/database_instances.py @@ -579,6 +579,28 @@ class RestartDatabaseInstance(command.Command): db_instances.restart(instance) +class EjectDatabaseInstanceReplicaSource(command.Command): + + _description = _("Ejects a replica source from its set.") + + def get_parser(self, prog_name): + parser = super(EjectDatabaseInstanceReplicaSource, self).get_parser( + prog_name) + parser.add_argument( + 'instance', + metavar='<instance>', + type=str, + help=_('ID or name of the instance.'), + ) + return parser + + def take_action(self, parsed_args): + db_instances = self.app.client_manager.database.instances + instance = osc_utils.find_resource(db_instances, + parsed_args.instance) + db_instances.eject_replica_source(instance) + + class UpdateDatabaseInstance(command.Command): _description = _("Updates an instance: Edits name, " @@ -633,3 +655,26 @@ class UpdateDatabaseInstance(command.Command): parsed_args.name, parsed_args.detach_replica_source, parsed_args.remove_configuration) + + +class DetachDatabaseInstanceReplica(command.Command): + + _description = _("Detaches a replica instance " + "from its replication source.") + + def get_parser(self, prog_name): + parser = super(DetachDatabaseInstanceReplica, self).get_parser( + prog_name) + parser.add_argument( + 'instance', + metavar='<instance>', + type=str, + help=_('ID or name of the instance.'), + ) + return parser + + def take_action(self, parsed_args): + db_instances = self.app.client_manager.database.instances + instance = osc_utils.find_resource(db_instances, + parsed_args.instance) + db_instances.edit(instance, detach_replica_source=True) diff --git a/troveclient/osc/v1/database_logs.py b/troveclient/osc/v1/database_logs.py new file mode 100644 index 0000000..aaba81e --- /dev/null +++ b/troveclient/osc/v1/database_logs.py @@ -0,0 +1,43 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Database v1 Logs action implementations""" + +from osc_lib.command import command +from osc_lib import utils as osc_utils + +from troveclient.i18n import _ + + +class ListDatabaseLogs(command.Lister): + + _description = _("Lists the log files available for instance.") + columns = ['Name', 'Type', 'Status', 'Published', 'Pending', + 'Container', 'Prefix'] + + def get_parser(self, prog_name): + parser = super(ListDatabaseLogs, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='<instance>', + help=_('ID or name of the instance.') + ) + return parser + + def take_action(self, parsed_args): + database_instances = self.app.client_manager.database.instances + instance = osc_utils.find_resource(database_instances, + parsed_args.instance) + log_list = database_instances.log_list(instance) + logs = [osc_utils.get_item_properties(l, self.columns) + for l in log_list] + return self.columns, logs diff --git a/troveclient/tests/fakes.py b/troveclient/tests/fakes.py index 7864054..55d13f7 100644 --- a/troveclient/tests/fakes.py +++ b/troveclient/tests/fakes.py @@ -527,7 +527,13 @@ class FakeHTTPClient(base_client.HTTPClient): return (200, {}, r) def get_configurations_c_123_instances(self, **kw): - return (200, {}, {"instances": []}) + return (200, {}, {"instances": [ + { + "id": "1", + "name": "instance-1"}, + { + "id": "2", + "name": "instance-2"}]}) def delete_configurations_c_123(self, **kw): return (202, {}, None) @@ -822,3 +828,25 @@ class FakeHTTPClient(base_client.HTTPClient): def update_instances_quota(self, **kw): return (200, {}, {"quotas": {"instances": 51}}) + + def get_logs(self, **kw): + return (200, {}, {"logs": [ + { + "name": "general", + "type": "USER", + "status": "Partial", + "published": "128", + "pending": "4096", + "container": "data_logs", + "prefix": "mysql-general", + "metafile": "mysql-general_metafile" + }, + { + "name": "slow_query", + "type": "USER", + "status": "Ready", + "published": "0", + "pending": "128", + "container": "None", + "prefix": "None", + "metafile": "mysql-slow_query_metafile"}]}) diff --git a/troveclient/tests/osc/v1/fakes.py b/troveclient/tests/osc/v1/fakes.py index 057c446..caca652 100644 --- a/troveclient/tests/osc/v1/fakes.py +++ b/troveclient/tests/osc/v1/fakes.py @@ -71,10 +71,22 @@ class FakeClusters(object): class FakeConfigurations(object): fake_config = (fakes.FakeHTTPClient().get_configurations() [2]['configurations']) + fake_config_instances = (fakes.FakeHTTPClient(). + get_configurations_c_123_instances()[2]) + fake_default_config = ( + fakes.FakeHTTPClient().get_instances_1234_configuration() + [2]['instance']) def get_configurations_c_123(self): return configurations.Configuration(None, self.fake_config[0]) + def get_configuration_instances(self): + return [instances.Instance(None, fake_instance) + for fake_instance in self.fake_config_instances['instances']] + + def get_default_configuration(self): + return instances.Instance(None, self.fake_default_config) + class FakeConfigurationParameters(object): fake_config_param = (fakes.FakeHTTPClient(). @@ -180,3 +192,11 @@ class FakeQuota(object): def get_quotas(self): return [quota.Quotas.resource_class(None, q) for q in self.fake_quotas] + + +class FakeLogs(object): + fake_logs = fakes.FakeHTTPClient().get_logs()[2]['logs'] + + def get_logs(self): + return [instances.DatastoreLog(None, fake_log) + for fake_log in self.fake_logs] diff --git a/troveclient/tests/osc/v1/test_database_backups.py b/troveclient/tests/osc/v1/test_database_backups.py index 4b1d10a..bbcaefe 100644 --- a/troveclient/tests/osc/v1/test_database_backups.py +++ b/troveclient/tests/osc/v1/test_database_backups.py @@ -206,3 +206,18 @@ class TestBackupCreate(TestBackups): description='backup 1234', parent_id='1234-1', incremental=True) + + +class TestDatabaseBackupExecutionDelete(TestBackups): + + def setUp(self): + super(TestDatabaseBackupExecutionDelete, self).setUp() + self.cmd = database_backups.DeleteDatabaseBackupExecution( + self.app, None) + + def test_execution_delete(self): + args = ['execution'] + parsed_args = self.check_parser(self.cmd, args, []) + result = self.cmd.take_action(parsed_args) + self.backup_client.execution_delete.assert_called_with('execution') + self.assertIsNone(result) diff --git a/troveclient/tests/osc/v1/test_database_configurations.py b/troveclient/tests/osc/v1/test_database_configurations.py index f48901b..2a2d64c 100644 --- a/troveclient/tests/osc/v1/test_database_configurations.py +++ b/troveclient/tests/osc/v1/test_database_configurations.py @@ -293,3 +293,61 @@ class TestConfigurationDetach(TestConfigurations): result = self.cmd.take_action(parsed_args) self.instance_client.modify.assert_called_with('instance2') self.assertIsNone(result) + + +class TestConfigurationInstancesList(TestConfigurations): + defaults = { + 'limit': None, + 'marker': None + } + + columns = ( + database_configurations.ListDatabaseConfigurationInstances.columns) + values = [('1', 'instance-1'), + ('2', 'instance-2')] + + def setUp(self): + super(TestConfigurationInstancesList, self).setUp() + self.cmd = database_configurations.ListDatabaseConfigurationInstances( + self.app, None) + data = ( + self.fake_configurations.get_configuration_instances()) + self.configuration_client.instances.return_value = common.Paginated( + data) + + @mock.patch.object(utils, 'find_resource') + def test_configuration_instances_list(self, mock_find): + args = ['c-123'] + mock_find.return_value = args[0] + parsed_args = self.check_parser(self.cmd, args, []) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.columns, columns) + self.assertEqual(self.values, data) + + +class TestConfigurationDefault(TestConfigurations): + + values = ('2', '98', '1', '15M') + + def setUp(self): + super(TestConfigurationDefault, self).setUp() + self.cmd = database_configurations.DefaultDatabaseConfiguration( + self.app, None) + self.data = ( + self.fake_configurations.get_default_configuration()) + self.instance_client.configuration.return_value = self.data + self.columns = ( + 'innodb_log_files_in_group', + 'max_user_connections', + 'skip-external-locking', + 'tmp_table_size', + ) + + @mock.patch.object(utils, 'find_resource') + def test_default_database_configuration(self, mock_find): + args = ['1234'] + mock_find.return_value = args[0] + parsed_args = self.check_parser(self.cmd, args, []) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.columns, columns) + self.assertEqual(self.values, data) diff --git a/troveclient/tests/osc/v1/test_database_instances.py b/troveclient/tests/osc/v1/test_database_instances.py index 83e6d3e..488a835 100644 --- a/troveclient/tests/osc/v1/test_database_instances.py +++ b/troveclient/tests/osc/v1/test_database_instances.py @@ -319,6 +319,24 @@ class TestDatabaseInstanceRestart(TestInstances): self.assertIsNone(result) +class TestDatabaseInstanceEjectReplicaSource(TestInstances): + + def setUp(self): + super(TestDatabaseInstanceEjectReplicaSource, self).setUp() + self.cmd = database_instances.EjectDatabaseInstanceReplicaSource( + self.app, None) + + @mock.patch.object(utils, 'find_resource') + def test_eject_replica_source(self, mock_find): + args = ['instance'] + mock_find.return_value = args[0] + parsed_args = self.check_parser(self.cmd, args, []) + result = self.cmd.take_action(parsed_args) + self.instance_client.eject_replica_source.assert_called_with( + 'instance') + self.assertIsNone(result) + + class TestDatabaseInstanceUpdate(TestInstances): def setUp(self): @@ -339,3 +357,21 @@ class TestDatabaseInstanceUpdate(TestInstances): 'new_instance_name', True, True) self.assertIsNone(result) + + +class TestInstanceReplicaDetach(TestInstances): + + def setUp(self): + super(TestInstanceReplicaDetach, self).setUp() + self.cmd = database_instances.DetachDatabaseInstanceReplica( + self.app, None) + + @mock.patch.object(utils, 'find_resource') + def test_instance_replica_detach(self, mock_find): + args = ['instance'] + mock_find.return_value = args[0] + parsed_args = self.check_parser(self.cmd, args, []) + result = self.cmd.take_action(parsed_args) + self.instance_client.edit.assert_called_with( + 'instance', detach_replica_source=True) + self.assertIsNone(result) diff --git a/troveclient/tests/osc/v1/test_database_logs.py b/troveclient/tests/osc/v1/test_database_logs.py new file mode 100644 index 0000000..1654380 --- /dev/null +++ b/troveclient/tests/osc/v1/test_database_logs.py @@ -0,0 +1,49 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from osc_lib import utils + +from troveclient.osc.v1 import database_logs +from troveclient.tests.osc.v1 import fakes + + +class TestLogs(fakes.TestDatabasev1): + fake_logs = fakes.FakeLogs() + + def setUp(self): + super(TestLogs, self).setUp() + self.instance_client = self.app.client_manager.database.instances + + +class TestLogList(TestLogs): + + columns = database_logs.ListDatabaseLogs.columns + values = [('general', 'USER', 'Partial', '128', '4096', 'data_logs', + 'mysql-general'), + ('slow_query', 'USER', 'Ready', '0', '128', 'None', 'None')] + + def setUp(self): + super(TestLogList, self).setUp() + self.cmd = database_logs.ListDatabaseLogs(self.app, None) + data = self.fake_logs.get_logs() + self.instance_client.log_list.return_value = data + + @mock.patch.object(utils, 'find_resource') + def test_log_list(self, mock_find): + args = ['instance'] + mock_find.return_value = args[0] + parsed_args = self.check_parser(self.cmd, args, []) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.columns, columns) + self.assertEqual(self.values, data) diff --git a/troveclient/v1/backups.py b/troveclient/v1/backups.py index 0ba18e7..f314fdc 100644 --- a/troveclient/v1/backups.py +++ b/troveclient/v1/backups.py @@ -243,7 +243,7 @@ class Backups(base.ManagerWithFind): yield the_item m = the_list[-1].id else: - raise StopIteration() + return def execution_list_generator(): yielded = 0 @@ -254,7 +254,7 @@ class Backups(base.ManagerWithFind): loaded=True) yielded += 1 if limit and yielded == limit: - raise StopIteration() + return return list(execution_list_generator()) |