Merge "Move scale managers at driver level"
This commit is contained in:
commit
06b97cc7d7
|
@ -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
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue