Merge "Move scale managers at driver level"

This commit is contained in:
Jenkins 2017-01-23 23:08:18 +00:00 committed by Gerrit Code Review
commit 06b97cc7d7
9 changed files with 105 additions and 72 deletions

View File

@ -13,11 +13,10 @@
# under the License. # under the License.
import abc import abc
from marathon import MarathonClient
from oslo_log import log as logging from oslo_log import log as logging
from magnum.common import exception from magnum.common import exception
from magnum.conductor import k8s_api as k8s from magnum.drivers.common.driver import Driver
from magnum.i18n import _ from magnum.i18n import _
from magnum.i18n import _LI from magnum.i18n import _LI
from magnum.i18n import _LW from magnum.i18n import _LW
@ -28,13 +27,9 @@ LOG = logging.getLogger(__name__)
def get_scale_manager(context, osclient, cluster): def get_scale_manager(context, osclient, cluster):
manager = None cluster_driver = Driver.get_driver_for_cluster(context, cluster)
coe = cluster.cluster_template.coe manager = cluster_driver.get_scale_manager(context, osclient, cluster)
if coe == 'kubernetes': if not manager:
manager = K8sScaleManager(context, osclient, cluster)
elif coe == 'mesos':
manager = MesosScaleManager(context, osclient, cluster)
else:
LOG.warning(_LW( LOG.warning(_LW(
"Currently only kubernetes and mesos cluster scale manager " "Currently only kubernetes and mesos cluster scale manager "
"are available")) "are available"))
@ -94,41 +89,3 @@ class ScaleManager(object):
def _get_hosts_with_container(self, context, cluster): def _get_hosts_with_container(self, context, cluster):
"""Return the hosts with container running on them.""" """Return the hosts with container running on them."""
pass pass
class K8sScaleManager(ScaleManager):
def __init__(self, context, osclient, cluster):
super(K8sScaleManager, self).__init__(context, osclient, cluster)
def _get_hosts_with_container(self, context, cluster):
k8s_api = k8s.create_k8s_api(self.context, cluster)
hosts = set()
for pod in k8s_api.list_namespaced_pod(namespace='default').items:
hosts.add(pod.spec.node_name)
return hosts
class MesosScaleManager(ScaleManager):
"""When scaling a mesos cluster, MesosScaleManager will inspect the
nodes and find out those with containers on them. Thus we can
ask Heat to delete the nodes without containers. Note that this
is a best effort basis -- Magnum doesn't have any synchronization
with Marathon, so while Magnum is checking for the containers to
choose nodes to remove, new containers can be deployed on the
nodes to be removed.
"""
def __init__(self, context, osclient, cluster):
super(MesosScaleManager, self).__init__(context, osclient, cluster)
def _get_hosts_with_container(self, context, cluster):
marathon_client = MarathonClient(
'http://' + cluster.api_address + ':8080')
hosts = set()
for task in marathon_client.list_tasks():
hosts.add(task.host)
return hosts

View File

@ -179,3 +179,8 @@ class Driver(object):
"""return the monitor with container data for this driver.""" """return the monitor with container data for this driver."""
return None return None
def get_scale_manager(self, context, osclient, cluster):
"""return the scale manager for this driver."""
return None

View File

@ -0,0 +1,33 @@
# 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.
from oslo_log import log as logging
from magnum.conductor import k8s_api as k8s
from magnum.conductor.scale_manager import ScaleManager
LOG = logging.getLogger(__name__)
class K8sScaleManager(ScaleManager):
def __init__(self, context, osclient, cluster):
super(K8sScaleManager, self).__init__(context, osclient, cluster)
def _get_hosts_with_container(self, context, cluster):
k8s_api = k8s.create_k8s_api(self.context, cluster)
hosts = set()
for pod in k8s_api.list_namespaced_pod(namespace='default').items:
hosts.add(pod.spec.node_name)
return hosts

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
from magnum.drivers.common import k8s_monitor from magnum.drivers.common import k8s_monitor
from magnum.drivers.common.k8s_scale_manager import K8sScaleManager
from magnum.drivers.heat import driver from magnum.drivers.heat import driver
from magnum.drivers.k8s_coreos_v1 import template_def from magnum.drivers.k8s_coreos_v1 import template_def
@ -32,3 +33,6 @@ class Driver(driver.HeatDriver):
def get_monitor(self, context, cluster): def get_monitor(self, context, cluster):
return k8s_monitor.K8sMonitor(context, cluster) return k8s_monitor.K8sMonitor(context, cluster)
def get_scale_manager(self, context, osclient, cluster):
return K8sScaleManager(context, osclient, cluster)

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
from magnum.drivers.common import k8s_monitor from magnum.drivers.common import k8s_monitor
from magnum.drivers.common.k8s_scale_manager import K8sScaleManager
from magnum.drivers.heat import driver from magnum.drivers.heat import driver
from magnum.drivers.k8s_fedora_atomic_v1 import template_def from magnum.drivers.k8s_fedora_atomic_v1 import template_def
@ -32,3 +33,6 @@ class Driver(driver.HeatDriver):
def get_monitor(self, context, cluster): def get_monitor(self, context, cluster):
return k8s_monitor.K8sMonitor(context, cluster) return k8s_monitor.K8sMonitor(context, cluster)
def get_scale_manager(self, context, osclient, cluster):
return K8sScaleManager(context, osclient, cluster)

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
from magnum.drivers.common import k8s_monitor from magnum.drivers.common import k8s_monitor
from magnum.drivers.common.k8s_scale_manager import K8sScaleManager
from magnum.drivers.heat import driver from magnum.drivers.heat import driver
from magnum.drivers.k8s_fedora_ironic_v1 import template_def from magnum.drivers.k8s_fedora_ironic_v1 import template_def
@ -32,3 +33,6 @@ class Driver(driver.HeatDriver):
def get_monitor(self, context, cluster): def get_monitor(self, context, cluster):
return k8s_monitor.K8sMonitor(context, cluster) return k8s_monitor.K8sMonitor(context, cluster)
def get_scale_manager(self, context, osclient, cluster):
return K8sScaleManager(context, osclient, cluster)

View File

@ -14,6 +14,7 @@
from magnum.drivers.heat import driver from magnum.drivers.heat import driver
from magnum.drivers.mesos_ubuntu_v1 import monitor from magnum.drivers.mesos_ubuntu_v1 import monitor
from magnum.drivers.mesos_ubuntu_v1.scale_manager import MesosScaleManager
from magnum.drivers.mesos_ubuntu_v1 import template_def from magnum.drivers.mesos_ubuntu_v1 import template_def
@ -32,3 +33,6 @@ class Driver(driver.HeatDriver):
def get_monitor(self, context, cluster): def get_monitor(self, context, cluster):
return monitor.MesosMonitor(context, cluster) return monitor.MesosMonitor(context, cluster)
def get_scale_manager(self, context, osclient, cluster):
return MesosScaleManager(context, osclient, cluster)

View File

@ -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.
from marathon import MarathonClient
from oslo_log import log as logging
from magnum.conductor.scale_manager import ScaleManager
LOG = logging.getLogger(__name__)
class MesosScaleManager(ScaleManager):
"""When scaling a mesos cluster, MesosScaleManager will inspect the
nodes and find out those with containers on them. Thus we can
ask Heat to delete the nodes without containers. Note that this
is a best effort basis -- Magnum doesn't have any synchronization
with Marathon, so while Magnum is checking for the containers to
choose nodes to remove, new containers can be deployed on the
nodes to be removed.
"""
def __init__(self, context, osclient, cluster):
super(MesosScaleManager, self).__init__(context, osclient, cluster)
def _get_hosts_with_container(self, context, cluster):
marathon_client = MarathonClient(
'http://' + cluster.api_address + ':8080')
hosts = set()
for task in marathon_client.list_tasks():
hosts.add(task.host)
return hosts

View File

@ -16,34 +16,13 @@ import mock
from magnum.common import exception from magnum.common import exception
from magnum.conductor import scale_manager from magnum.conductor import scale_manager
from magnum.drivers.common.k8s_scale_manager import K8sScaleManager
from magnum.drivers.mesos_ubuntu_v1.scale_manager import MesosScaleManager
from magnum.tests import base from magnum.tests import base
class TestScaleManager(base.TestCase): class TestScaleManager(base.TestCase):
@mock.patch('magnum.objects.Cluster.get_by_uuid')
def test_get_scale_manager(self, mock_cluster_get):
mock_context = mock.MagicMock()
mock_osc = mock.MagicMock()
k8s_cluster = mock.MagicMock()
k8s_cluster.cluster_template.coe = 'kubernetes'
mesos_cluster = mock.MagicMock()
mesos_cluster.cluster_template.coe = 'mesos'
invalid_cluster = mock.MagicMock()
invalid_cluster.cluster_template.coe = 'fake'
mgr = scale_manager.get_scale_manager(
mock_context, mock_osc, k8s_cluster)
self.assertIsInstance(mgr, scale_manager.K8sScaleManager)
mgr = scale_manager.get_scale_manager(
mock_context, mock_osc, mesos_cluster)
self.assertIsInstance(mgr, scale_manager.MesosScaleManager)
mgr = scale_manager.get_scale_manager(
mock_context, mock_osc, invalid_cluster)
self.assertIsNone(mgr)
def _test_get_removal_nodes( def _test_get_removal_nodes(
self, mock_get_hosts, mock_get_num_of_removal, self, mock_get_hosts, mock_get_num_of_removal,
mock_is_scale_down, mock_get_by_uuid, is_scale_down, mock_is_scale_down, mock_get_by_uuid, is_scale_down,
@ -215,7 +194,7 @@ class TestK8sScaleManager(base.TestCase):
mock_api.list_namespaced_pod.return_value = pods mock_api.list_namespaced_pod.return_value = pods
mock_create_api.return_value = mock_api mock_create_api.return_value = mock_api
mgr = scale_manager.K8sScaleManager( mgr = K8sScaleManager(
mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
hosts = mgr._get_hosts_with_container( hosts = mgr._get_hosts_with_container(
mock.MagicMock(), mock.MagicMock()) mock.MagicMock(), mock.MagicMock())
@ -236,7 +215,7 @@ class TestMesosScaleManager(base.TestCase):
tasks = [task_1, task_2] tasks = [task_1, task_2]
mock_list_tasks.return_value = tasks mock_list_tasks.return_value = tasks
mgr = scale_manager.MesosScaleManager( mgr = MesosScaleManager(
mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
hosts = mgr._get_hosts_with_container( hosts = mgr._get_hosts_with_container(
mock.MagicMock(), mock.MagicMock()) mock.MagicMock(), mock.MagicMock())