From 9158062bde6170c3b5e556577e2a3d5a0e96125d Mon Sep 17 00:00:00 2001 From: Vitaly Gridnev Date: Fri, 13 May 2016 13:26:51 +0300 Subject: [PATCH] remove config groups associated with removed hosts this change will remove config groups associated with hosts which were removed during decommission. Change-Id: Ie345784fad0a3c258645f91ff0708f01e3530886 Closes-bug: 1573512 --- ...config-groups-ambari-837de6d33eb0fa87.yaml | 4 + sahara/plugins/ambari/client.py | 17 ++++ sahara/plugins/ambari/deploy.py | 16 ++++ sahara/plugins/ambari/plugin.py | 1 + .../tests/unit/plugins/ambari/test_deploy.py | 80 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 releasenotes/notes/config-groups-ambari-837de6d33eb0fa87.yaml create mode 100644 sahara/tests/unit/plugins/ambari/test_deploy.py diff --git a/releasenotes/notes/config-groups-ambari-837de6d33eb0fa87.yaml b/releasenotes/notes/config-groups-ambari-837de6d33eb0fa87.yaml new file mode 100644 index 00000000..0142de7c --- /dev/null +++ b/releasenotes/notes/config-groups-ambari-837de6d33eb0fa87.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - After decommissioning hosts all assoicated configs groups + will be removed in ambari plugin. diff --git a/sahara/plugins/ambari/client.py b/sahara/plugins/ambari/client.py index f76f0d93..d38eb559 100644 --- a/sahara/plugins/ambari/client.py +++ b/sahara/plugins/ambari/client.py @@ -131,6 +131,23 @@ class AmbariClient(object): resp = self.post(url) self.check_response(resp) + def get_config_groups(self, cluster): + url = self._base_url + "/clusters/%s/config_groups" % cluster.name + resp = self.get(url) + return self.check_response(resp) + + def get_detailed_config_group(self, cluster, cfg_id): + url = self._base_url + "/clusters/%s/config_groups/%s" % ( + cluster.name, cfg_id) + resp = self.get(url) + return self.check_response(resp) + + def remove_config_group(self, cluster, cfg_id): + url = self._base_url + "/clusters/%s/config_groups/%s" % ( + cluster.name, cfg_id) + resp = self.delete(url) + return self.check_response(resp) + def create_config_group(self, cluster, data): url = self._base_url + "/clusters/%s/config_groups" % cluster.name resp = self.post(url, data=jsonutils.dumps(data)) diff --git a/sahara/plugins/ambari/deploy.py b/sahara/plugins/ambari/deploy.py index 2869c5a5..f21742e5 100644 --- a/sahara/plugins/ambari/deploy.py +++ b/sahara/plugins/ambari/deploy.py @@ -291,6 +291,22 @@ def manage_config_groups(cluster, instances): client.create_config_group(cluster, groups) +def cleanup_config_groups(cluster, instances): + to_remove = set() + for instance in instances: + cfg_name = "%s:%s" % (cluster.name, instance.instance_name) + to_remove.add(cfg_name) + with _get_ambari_client(cluster) as client: + config_groups = client.get_config_groups(cluster) + for group in config_groups['items']: + cfg_id = group['ConfigGroup']['id'] + detailed = client.get_detailed_config_group(cluster, cfg_id) + cfg_name = detailed['ConfigGroup']['group_name'] + # we have config group per host + if cfg_name in to_remove: + client.remove_config_group(cluster, cfg_id) + + def manage_host_components(cluster, instances): requests_ids = [] with _get_ambari_client(cluster) as client: diff --git a/sahara/plugins/ambari/plugin.py b/sahara/plugins/ambari/plugin.py index 31a81c63..dbcac1cb 100644 --- a/sahara/plugins/ambari/plugin.py +++ b/sahara/plugins/ambari/plugin.py @@ -191,6 +191,7 @@ class AmbariPluginProvider(p.ProvisioningPluginBase): deploy.decommission_hosts(cluster, instances) deploy.remove_services_from_hosts(cluster, instances) deploy.restart_nns_and_rms(cluster) + deploy.cleanup_config_groups(cluster, instances) def validate_scaling(self, cluster, existing, additional): validation.validate(cluster.id) diff --git a/sahara/tests/unit/plugins/ambari/test_deploy.py b/sahara/tests/unit/plugins/ambari/test_deploy.py new file mode 100644 index 00000000..71517cce --- /dev/null +++ b/sahara/tests/unit/plugins/ambari/test_deploy.py @@ -0,0 +1,80 @@ +# Copyright (c) 2016 Mirantis Inc. +# +# 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 oslo_serialization import jsonutils + +from sahara.plugins.ambari import deploy +from sahara.tests.unit import base + + +class TestDeploy(base.SaharaTestCase): + @mock.patch('sahara.plugins.utils.get_instance') + @mock.patch('sahara.plugins.ambari.client.AmbariClient.get') + @mock.patch('sahara.plugins.ambari.client.AmbariClient.delete') + def test_cleanup_config_groups(self, client_delete, client_get, + get_instance): + def response(data): + fake = mock.Mock() + fake.text = jsonutils.dumps(data) + fake.raise_for_status.return_value = True + return fake + + fake_config_groups = { + 'items': [ + {'ConfigGroup': {'id': "1"}}, + {'ConfigGroup': {'id': "2"}} + ] + } + + config_group1 = { + 'ConfigGroup': {'id': '1', 'group_name': "test:fakename"}} + config_group2 = { + 'ConfigGroup': {'id': '2', 'group_name': "test:toremove"}} + + fake_ambari = mock.Mock() + fake_ambari.management_ip = "127.0.0.1" + get_instance.return_value = fake_ambari + + inst1 = mock.Mock() + inst1.instance_name = "toremove" + + cl = mock.Mock(extra={'ambari_password': "SUPER_STRONG"}) + cl.name = "test" + + client_get.side_effect = [ + response(fake_config_groups), response(config_group1), + response(config_group2) + ] + client_delete.side_effect = [response({})] + + deploy.cleanup_config_groups(cl, [inst1]) + get_calls = [ + mock.call( + 'http://127.0.0.1:8080/api/v1/clusters/test/config_groups'), + mock.call( + 'http://127.0.0.1:8080/api/v1/clusters/test/config_groups/1'), + mock.call( + 'http://127.0.0.1:8080/api/v1/clusters/test/config_groups/2') + ] + + self.assertEqual(get_calls, client_get.call_args_list) + + delete_calls = [ + mock.call( + 'http://127.0.0.1:8080/api/v1/clusters/test/config_groups/2') + ] + + self.assertEqual(delete_calls, client_delete.call_args_list)