diff --git a/trove_dashboard/content/database_configurations/config_param_manager.py b/trove_dashboard/content/database_configurations/config_param_manager.py
index 817de60..069a35e 100644
--- a/trove_dashboard/content/database_configurations/config_param_manager.py
+++ b/trove_dashboard/content/database_configurations/config_param_manager.py
@@ -22,8 +22,8 @@ from trove_dashboard import api
from oslo_serialization import jsonutils
-def get(request, configuration_group_id):
- if not has_config(configuration_group_id):
+def get(request, configuration_group_id, use_cache=False):
+ if not use_cache or not has_config(configuration_group_id):
manager = ConfigParamManager(configuration_group_id)
manager.configuration_get(request)
cache.cache.set(configuration_group_id, manager)
diff --git a/trove_dashboard/content/database_configurations/forms.py b/trove_dashboard/content/database_configurations/forms.py
index 8a784df..42494a7 100644
--- a/trove_dashboard/content/database_configurations/forms.py
+++ b/trove_dashboard/content/database_configurations/forms.py
@@ -174,12 +174,19 @@ class AddParameterForm(forms.SelfHandlingForm):
def handle(self, request, data):
try:
(config_param_manager
- .get(request, self.initial["configuration_id"])
- .add_param(data["name"],
- config_param_manager.adjust_type(
- config_param_manager.find_parameter(
- data["name"], self.parameters).type,
- data["value"])))
+ .get(request, self.initial["configuration_id"])
+ .add_param(data["name"],
+ config_param_manager.adjust_type(
+ config_param_manager.find_parameter(
+ data["name"], self.parameters).type,
+ data["value"])))
+
+ new_values = config_param_manager.get(
+ request, self.initial["configuration_id"], use_cache=True
+ ).to_json()
+ api.trove.configuration_update(
+ request, self.initial["configuration_id"], new_values)
+
messages.success(request, _('Successfully added parameter'))
except Exception:
redirect = reverse("horizon:project:database_configurations:index")
diff --git a/trove_dashboard/content/database_configurations/tables.py b/trove_dashboard/content/database_configurations/tables.py
index 74a3824..55622cb 100644
--- a/trove_dashboard/content/database_configurations/tables.py
+++ b/trove_dashboard/content/database_configurations/tables.py
@@ -20,6 +20,7 @@ from django.utils.translation import ungettext_lazy
from horizon import forms
from horizon import messages
from horizon import tables
+from oslo_serialization import jsonutils
from trove_dashboard import api
from trove_dashboard.content.database_configurations \
@@ -162,11 +163,20 @@ class DeleteParameter(tables.DeleteAction):
count
)
- def delete(self, request, obj_ids):
+ def delete(self, request, names):
+ if type(names) is not list:
+ names = [names]
+
configuration_id = self.table.kwargs['configuration_id']
- (config_param_manager
- .get(request, configuration_id)
- .delete_param(obj_ids))
+ configuration = api.trove.configuration_get(request, configuration_id)
+ cur_values = dict.copy(configuration.values)
+
+ for name in names:
+ if name in cur_values:
+ cur_values.pop(name)
+
+ api.trove.configuration_update(
+ request, configuration_id, jsonutils.dumps(cur_values))
class UpdateRow(tables.Row):
@@ -183,8 +193,7 @@ class ValuesTable(tables.DataTable):
class Meta(object):
name = "values"
verbose_name = _("Configuration Group Values")
- table_actions = [ApplyChanges, DiscardChanges,
- AddParameter, DeleteParameter]
+ table_actions = [AddParameter, DeleteParameter]
row_class = UpdateRow
row_actions = [DeleteParameter]
diff --git a/trove_dashboard/content/database_configurations/templates/database_configurations/detail_param.html b/trove_dashboard/content/database_configurations/templates/database_configurations/detail_param.html
index 5df8d50..b3b7e51 100644
--- a/trove_dashboard/content/database_configurations/templates/database_configurations/detail_param.html
+++ b/trove_dashboard/content/database_configurations/templates/database_configurations/detail_param.html
@@ -2,7 +2,7 @@
- {% trans "Add parameters to the configuration group. When all the parameters are added click 'Apply Changes' to persist changes." %}
+ {% trans "Manage parameters of the configuration group. If the configuration group is attached with database instance, the change is applied to the instance synchronously." %}
{{ table.render }}
diff --git a/trove_dashboard/content/database_configurations/tests.py b/trove_dashboard/content/database_configurations/tests.py
index 004fd70..ff1ea98 100644
--- a/trove_dashboard/content/database_configurations/tests.py
+++ b/trove_dashboard/content/database_configurations/tests.py
@@ -15,16 +15,14 @@
import logging
from unittest import mock
-import django
-from django.conf import settings
from django.urls import reverse
+from oslo_serialization import jsonutils
from trove_dashboard import api
from trove_dashboard.content.database_configurations \
import config_param_manager
from trove_dashboard.test import helpers as test
-
INDEX_URL = reverse('horizon:project:database_configurations:index')
CREATE_URL = reverse('horizon:project:database_configurations:create')
DETAIL_URL = 'horizon:project:database_configurations:detail'
@@ -94,8 +92,7 @@ class DatabaseConfigurationsTests(test.TestCase):
@test.create_mocks({
api.trove: ('datastore_list', 'datastore_version_list',
'configuration_create')})
- def _test_create_test_configuration(
- self, config_description=u''):
+ def _test_create_test_configuration(self, config_description=u''):
self.mock_datastore_list.return_value = self.datastores.list()
self.mock_datastore_version_list.return_value = (
self.datastore_versions.list())
@@ -182,8 +179,7 @@ class DatabaseConfigurationsTests(test.TestCase):
details_url = self._get_url_with_arg(DETAIL_URL, config.id)
url = details_url + '?tab=configuration_details__details'
res = self.client.get(url)
- self.mock_configuration_get.assert_called_once_with(
- test.IsHttpRequest(), config.id)
+ self.assertEqual(2, self.mock_configuration_get.call_count)
self.assertTemplateUsed(res,
'project/database_configurations/details.html')
@@ -253,11 +249,12 @@ class DatabaseConfigurationsTests(test.TestCase):
self.mock_get_configuration.assert_called_once()
self.mock_configuration_get.assert_called_once_with(
test.IsHttpRequest())
- (self.mock_configuration_parameters_list
- .assert_called_once_with(
- test.IsHttpRequest(),
- ds.name,
- dsv.name))
+ self.mock_configuration_parameters_list. \
+ assert_called_once_with(
+ test.IsHttpRequest(),
+ ds.name,
+ dsv.name
+ )
self.assertEqual(res.status_code, 302)
finally:
@@ -267,13 +264,17 @@ class DatabaseConfigurationsTests(test.TestCase):
finally:
config_param_manager.delete(config.id)
- @test.create_mocks({
- api.trove: ('configuration_parameters_list',),
- config_param_manager.ConfigParamManager:
- ('get_configuration', 'add_param', 'configuration_get',)})
+ @test.create_mocks(
+ {
+ api.trove:
+ ('configuration_parameters_list', 'configuration_update',
+ 'configuration_get'),
+ config_param_manager.ConfigParamManager: ('add_param',)
+ }
+ )
def test_add_new_parameter(self):
config = self.database_configurations.first()
- self.mock_get_configuration.return_value = config
+
try:
self.mock_configuration_get.return_value = config
@@ -284,6 +285,7 @@ class DatabaseConfigurationsTests(test.TestCase):
name = self.configuration_parameters.first().name
value = 1
+ config.values.update({name: value})
self.mock_add_param.return_value = value
@@ -294,14 +296,17 @@ class DatabaseConfigurationsTests(test.TestCase):
res = self.client.post(self._get_url_with_arg(ADD_URL, config.id),
post)
- self.mock_get_configuration.assert_called_once()
- self.mock_configuration_get.assert_called_once_with(
- test.IsHttpRequest())
+
+ self.assertEqual(2, self.mock_configuration_get.call_count)
self.mock_configuration_parameters_list.assert_called_once_with(
test.IsHttpRequest(),
ds.name,
dsv.name)
self.mock_add_param.assert_called_once_with(name, value)
+ self.mock_configuration_update.assert_called_once_with(
+ test.IsHttpRequest(), config.id,
+ jsonutils.dumps(config.values)
+ )
self.assertNoFormErrors(res)
self.assertMessageCount(success=1)
finally:
@@ -346,156 +351,6 @@ class DatabaseConfigurationsTests(test.TestCase):
finally:
config_param_manager.delete(config.id)
- @test.create_mocks({api.trove: ('configuration_get',
- 'configuration_instances',)})
- def test_values_tab_discard_action(self):
- config = self.database_configurations.first()
-
- self.mock_configuration_get.return_value = config
-
- details_url = self._get_url_with_arg(DETAIL_URL, config.id)
- url = details_url + '?tab=configuration_details__value'
-
- self._test_create_altered_config_params(config, url)
-
- # get the state of the configuration before discard action
- changed_configuration_values = \
- dict.copy(config_param_manager.get(self.request, config.id)
- .get_configuration().values)
-
- res = self.client.post(url, {'action': u"values__discard_changes"})
- self.mock_configuration_get.assert_called_once_with(
- test.IsHttpRequest(), config.id)
- if django.VERSION >= (1, 9):
- url = settings.TESTSERVER + url
- self.assertRedirectsNoFollow(res, url)
-
- # get the state of the configuration after discard action
- restored_configuration_values = \
- dict.copy(config_param_manager.get(self.request, config.id)
- .get_configuration().values)
-
- self.assertTrue(config_param_manager.dict_has_changes(
- changed_configuration_values, restored_configuration_values))
-
- @test.create_mocks({api.trove: ('configuration_instances',
- 'configuration_update',),
- config_param_manager: ('get',)})
- def test_values_tab_apply_action(self):
- # NOTE(zhaochao): we cannot use copy.deepcopy() under Python 3,
- # because of the lazy-loading feature of the troveclient Resource
- # objects. copy.deepcopy will use hasattr to search for the
- # '__setstate__' attribute of the resource object. As the resource
- # object is lazy loading, searching attributes relys on the 'is_load'
- # property, unfortunately this property is also not loaded at the
- # moment, then we're getting in an infinite loop there. Python will
- # raise RuntimeError saying "maximum recursion depth exceeded", this is
- # ignored under Python 2.x, but reraised under Python 3 by hasattr().
- #
- # Temporarily importing troveclient and reconstructing a configuration
- # object from the original config object's dict info will make this
- # case (and the next) working under Python 3.
- original_config = self.database_configurations.first()
- from troveclient.v1 import configurations
- config = configurations.Configuration(
- configurations.Configurations(None), original_config.to_dict())
- # Making sure the newly constructed config object is the same as
- # the original one.
- self.assertEqual(config, original_config)
-
- # setup the configuration parameter manager
- config_param_mgr = config_param_manager.ConfigParamManager(
- config.id)
- config_param_mgr.configuration = config
- config_param_mgr.original_configuration_values = \
- dict.copy(config.values)
-
- self.mock_get.return_value = config_param_mgr
-
- self.mock_configuration_update.return_value = None
-
- details_url = self._get_url_with_arg(DETAIL_URL, config.id)
- url = details_url + '?tab=configuration_details__value'
-
- self._test_create_altered_config_params(config, url)
-
- # apply changes
- res = self.client.post(url, {'action': u"values__apply_changes"})
- self.assert_mock_multiple_calls_with_same_arguments(
- self.mock_get, 11, mock.call(test.IsHttpRequest(), config.id))
- self.mock_configuration_update.assert_called_once_with(
- test.IsHttpRequest(),
- config.id,
- config_param_mgr.to_json())
- if django.VERSION >= (1, 9):
- url = settings.TESTSERVER + url
- self.assertRedirectsNoFollow(res, url)
-
- @test.create_mocks({api.trove: ('configuration_instances',
- 'configuration_update',),
- config_param_manager: ('get',)})
- def test_values_tab_apply_action_exception(self):
- # NOTE(zhaochao) Please refer to the comment at the beginning of the
- # 'test_values_tab_apply_action' about not using copy.deepcopy() for
- # details.
- original_config = self.database_configurations.first()
- from troveclient.v1 import configurations
- config = configurations.Configuration(
- configurations.Configurations(None), original_config.to_dict())
- # Making sure the newly constructed config object is the same as
- # the original one.
- self.assertEqual(config, original_config)
-
- # setup the configuration parameter manager
- config_param_mgr = config_param_manager.ConfigParamManager(
- config.id)
- config_param_mgr.configuration = config
- config_param_mgr.original_configuration_values = \
- dict.copy(config.values)
-
- self.mock_get.return_value = config_param_mgr
-
- self.mock_configuration_update.side_effect = self.exceptions.trove
-
- details_url = self._get_url_with_arg(DETAIL_URL, config.id)
- url = details_url + '?tab=configuration_details__value'
-
- self._test_create_altered_config_params(config, url)
-
- # apply changes
- res = self.client.post(url, {'action': u"values__apply_changes"})
- self.assert_mock_multiple_calls_with_same_arguments(
- self.mock_get, 11, mock.call(test.IsHttpRequest(), config.id))
- self.mock_configuration_update.assert_called_once_with(
- test.IsHttpRequest(),
- config.id,
- config_param_mgr.to_json())
- if django.VERSION >= (1, 9):
- url = settings.TESTSERVER + url
- self.assertRedirectsNoFollow(res, url)
- self.assertEqual(res.status_code, 302)
-
- def _test_create_altered_config_params(self, config, url):
- # determine the number of configuration group parameters in the list
- res = self.client.get(url)
-
- table_data = res.context['table'].data
- number_params = len(table_data)
- config_param = table_data[0]
-
- # delete the first parameter
- action_string = u"values__delete__%s" % config_param.name
- form_data = {'action': action_string}
- res = self.client.post(url, form_data)
- self.assertRedirectsNoFollow(res, url)
-
- # verify the test number of parameters is reduced by 1
- res = self.client.get(url)
- table_data = res.context['table'].data
- new_number_params = len(table_data)
-
- self.assertEqual((number_params - 1), new_number_params)
-
@test.create_mocks({api.trove: ('configuration_instances',),
config_param_manager: ('get',)})
def test_instances_tab(self):