Merge "Support autoscaling for the default node group"
This commit is contained in:
commit
c5e8e14ba8
@ -584,6 +584,31 @@ class Driver(driver.Driver):
|
||||
def _get_autoheal_enabled(self, cluster):
|
||||
return self._get_label_bool(cluster, "auto_healing_enabled", True)
|
||||
|
||||
def _get_autoscale(self, cluster, nodegroup):
|
||||
auto_scale = self._get_label_bool(
|
||||
cluster, "auto_scaling_enabled", False
|
||||
)
|
||||
if auto_scale:
|
||||
auto_scale_args = dict(autoscale="true")
|
||||
min_nodes = max(1, nodegroup.min_node_count)
|
||||
max_nodes = self._get_label_int(
|
||||
cluster, "max_node_count", min_nodes
|
||||
)
|
||||
if min_nodes > nodegroup.node_count:
|
||||
raise exception.MagnumException(
|
||||
message="min_node_count must be less than or equal to "
|
||||
"default-worker nodegroup node_count."
|
||||
)
|
||||
auto_scale_args["machineCountMin"] = min_nodes
|
||||
if max_nodes < min_nodes:
|
||||
raise exception.MagnumException(
|
||||
message="max_node_count must be greater than or "
|
||||
"equal to min_node_count"
|
||||
)
|
||||
auto_scale_args["machineCountMax"] = max_nodes
|
||||
return auto_scale_args
|
||||
return auto_scale
|
||||
|
||||
def _get_k8s_keystone_auth_enabled(self, cluster):
|
||||
return self._get_label_bool(cluster, "keystone_auth_enabled", False)
|
||||
|
||||
@ -728,6 +753,26 @@ class Driver(driver.Driver):
|
||||
additionalStorageClasses=additional_storage_classes,
|
||||
)
|
||||
|
||||
def _process_node_groups(self, cluster):
|
||||
nodegroups = cluster.nodegroups
|
||||
nodegroup_set = []
|
||||
for ng in nodegroups:
|
||||
if ng.role != NODE_GROUP_ROLE_CONTROLLER:
|
||||
nodegroup_item = dict(
|
||||
name=driver_utils.sanitized_name(ng.name),
|
||||
machineFlavor=ng.flavor_id,
|
||||
machineCount=ng.node_count,
|
||||
)
|
||||
# Assume first nodegroup is default-worker.
|
||||
if not nodegroup_set:
|
||||
auto_scale = self._get_autoscale(cluster, ng)
|
||||
if auto_scale:
|
||||
nodegroup_item = helm.mergeconcat(
|
||||
nodegroup_item, auto_scale
|
||||
)
|
||||
nodegroup_set.append(nodegroup_item)
|
||||
return nodegroup_set
|
||||
|
||||
def _update_helm_release(self, context, cluster, nodegroups=None):
|
||||
if nodegroups is None:
|
||||
nodegroups = cluster.nodegroups
|
||||
@ -778,15 +823,7 @@ class Driver(driver.Driver):
|
||||
"enabled": self._get_autoheal_enabled(cluster),
|
||||
},
|
||||
},
|
||||
"nodeGroups": [
|
||||
{
|
||||
"name": driver_utils.sanitized_name(ng.name),
|
||||
"machineFlavor": ng.flavor_id,
|
||||
"machineCount": ng.node_count,
|
||||
}
|
||||
for ng in nodegroups
|
||||
if ng.role != NODE_GROUP_ROLE_CONTROLLER
|
||||
],
|
||||
"nodeGroups": self._process_node_groups(cluster),
|
||||
"addons": {
|
||||
"openstack": {
|
||||
"csiCinder": self._storageclass_definitions(
|
||||
|
@ -2695,3 +2695,129 @@ class ClusterAPIDriverTest(base.DbTestCase):
|
||||
.get("LoadBalancer", {})
|
||||
.get("create-monitor")
|
||||
)
|
||||
|
||||
def test_validate_auto_scale_max_lt_min(self):
|
||||
self.cluster_obj.labels = dict(
|
||||
auto_scaling_enabled="true", min_node_count=3, max_node_count=0
|
||||
)
|
||||
self.assertRaises(
|
||||
exception.MagnumException,
|
||||
self.driver._get_autoscale,
|
||||
self.cluster_obj,
|
||||
self.cluster_obj.nodegroups[0],
|
||||
)
|
||||
|
||||
@mock.patch.object(
|
||||
driver.Driver, "_get_k8s_keystone_auth_enabled", return_value=False
|
||||
)
|
||||
@mock.patch.object(
|
||||
driver.Driver,
|
||||
"_storageclass_definitions",
|
||||
return_value=mock.ANY,
|
||||
)
|
||||
@mock.patch.object(driver.Driver, "_validate_allowed_flavor")
|
||||
@mock.patch.object(neutron, "get_network", autospec=True)
|
||||
@mock.patch.object(
|
||||
driver.Driver, "_ensure_certificate_secrets", autospec=True
|
||||
)
|
||||
@mock.patch.object(driver.Driver, "_create_appcred_secret", autospec=True)
|
||||
@mock.patch.object(kubernetes.Client, "load", autospec=True)
|
||||
@mock.patch.object(driver.Driver, "_get_image_details", autospec=True)
|
||||
@mock.patch.object(helm.Client, "install_or_upgrade", autospec=True)
|
||||
def test_create_cluster_auto_scale_enabled(
|
||||
self,
|
||||
mock_install,
|
||||
mock_image,
|
||||
mock_load,
|
||||
mock_appcred,
|
||||
mock_certs,
|
||||
mock_get_net,
|
||||
mock_validate_allowed_flavor,
|
||||
mock_storageclasses,
|
||||
mock_get_keystone_auth_enabled,
|
||||
):
|
||||
auto_scale_labels = dict(
|
||||
auto_scaling_enabled="true", min_node_count=2, max_node_count=6
|
||||
)
|
||||
self.cluster_obj.labels = auto_scale_labels
|
||||
|
||||
mock_image.return_value = (
|
||||
"imageid1",
|
||||
"1.27.4",
|
||||
"ubuntu",
|
||||
)
|
||||
mock_client = mock.MagicMock(spec=kubernetes.Client)
|
||||
mock_load.return_value = mock_client
|
||||
|
||||
self.driver.create_cluster(self.context, self.cluster_obj, 10)
|
||||
helm_install_values = mock_install.call_args[0][3]
|
||||
self.assertEqual(
|
||||
helm_install_values["nodeGroups"][0]["autoscale"],
|
||||
auto_scale_labels["auto_scaling_enabled"],
|
||||
)
|
||||
# min_node_count is hardcode to max(1, ng.min_node_count)
|
||||
self.assertEqual(
|
||||
helm_install_values["nodeGroups"][0]["machineCountMin"],
|
||||
self.cluster_obj.nodegroups[0].min_node_count,
|
||||
)
|
||||
self.assertEqual(
|
||||
helm_install_values["nodeGroups"][0]["machineCountMax"],
|
||||
auto_scale_labels["max_node_count"],
|
||||
)
|
||||
|
||||
@mock.patch.object(
|
||||
driver.Driver, "_get_k8s_keystone_auth_enabled", return_value=False
|
||||
)
|
||||
@mock.patch.object(
|
||||
driver.Driver,
|
||||
"_storageclass_definitions",
|
||||
return_value=mock.ANY,
|
||||
)
|
||||
@mock.patch.object(driver.Driver, "_validate_allowed_flavor")
|
||||
@mock.patch.object(neutron, "get_network", autospec=True)
|
||||
@mock.patch.object(
|
||||
driver.Driver, "_ensure_certificate_secrets", autospec=True
|
||||
)
|
||||
@mock.patch.object(driver.Driver, "_create_appcred_secret", autospec=True)
|
||||
@mock.patch.object(kubernetes.Client, "load", autospec=True)
|
||||
@mock.patch.object(driver.Driver, "_get_image_details", autospec=True)
|
||||
@mock.patch.object(helm.Client, "install_or_upgrade", autospec=True)
|
||||
def test_create_cluster_auto_scale_disabled(
|
||||
self,
|
||||
mock_install,
|
||||
mock_image,
|
||||
mock_load,
|
||||
mock_appcred,
|
||||
mock_certs,
|
||||
mock_get_net,
|
||||
mock_validate_allowed_flavor,
|
||||
mock_storageclasses,
|
||||
mock_get_keystone_auth_enabled,
|
||||
):
|
||||
auto_scale_labels = dict(
|
||||
auto_scaling_enabled="false", min_node_count=2, max_node_count=6
|
||||
)
|
||||
self.cluster_obj.labels = auto_scale_labels
|
||||
|
||||
mock_image.return_value = (
|
||||
"imageid1",
|
||||
"1.27.4",
|
||||
"ubuntu",
|
||||
)
|
||||
mock_client = mock.MagicMock(spec=kubernetes.Client)
|
||||
mock_load.return_value = mock_client
|
||||
|
||||
self.driver.create_cluster(self.context, self.cluster_obj, 10)
|
||||
helm_install_values = mock_install.call_args[0][3]
|
||||
self.assertNotIn(
|
||||
"autoscale",
|
||||
helm_install_values["nodeGroups"][0],
|
||||
)
|
||||
self.assertNotIn(
|
||||
"machineCountMin",
|
||||
helm_install_values["nodeGroups"][0],
|
||||
)
|
||||
self.assertNotIn(
|
||||
"machineCountMax",
|
||||
helm_install_values["nodeGroups"][0],
|
||||
)
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for autoscaling of the default worker node group by respecting the
|
||||
`min_node_count` and `max_node_count` cluster labels. Unlike the Heat driver,
|
||||
when these labels are provided, the cluster will always start with node count
|
||||
equal to the minimum node count value and the alternative `node_count` flag will
|
||||
be ignored.
|
Loading…
Reference in New Issue
Block a user