Skip to content

Commit

Permalink
feat: set disableAPIServerFloatingIP as optional boolean (#486)
Browse files Browse the repository at this point in the history
  • Loading branch information
okozachenko1203 authored Feb 7, 2025
1 parent 7044ba8 commit 0b0295b
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ site
*.orig
*.rej
.tox
.stestr
10 changes: 9 additions & 1 deletion hack/stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@ sudo chown -R ${USER}. /opt/stack

# Clone repository if not present, otherwise update
if [ ! -f /opt/stack/stack.sh ]; then
git clone https://git.openstack.org/openstack-dev/devstack /opt/stack
git clone https://github.com/openstack/devstack /opt/stack
else
pushd /opt/stack
git pull
popd
fi

# Backport Magnum trusts fix
pushd /opt/stack
git clone https://github.com/openstack/magnum
cd magnum
git fetch https://review.opendev.org/openstack/magnum refs/changes/15/940815/1 && git checkout FETCH_HEAD
popd

# Create DevStack configuration file
cat <<EOF > /opt/stack/local.conf
[[local|localrc]]
# General
GIT_BASE=https://github.com
RECLONE=no
# Secrets
DATABASE_PASSWORD=root
Expand Down
71 changes: 49 additions & 22 deletions magnum_cluster_api/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ def delete(self):


class Base:
def __init__(self, api: pykube.HTTPClient):
def __init__(self, api: pykube.HTTPClient, namespace="magnum-system"):
self.api = api
self.namespace = namespace

def apply(self) -> None:
resource = self.get_object()
Expand All @@ -167,14 +168,18 @@ def delete(self) -> None:


class Namespace(Base):
def __init__(self, api: pykube.HTTPClient, name="magnum-system"):
super().__init__(api, name)
self.name = name

def get_object(self) -> pykube.Namespace:
return pykube.Namespace(
self.api,
{
"apiVersion": pykube.Namespace.version,
"kind": pykube.Namespace.kind,
"metadata": {
"name": "magnum-system",
"name": self.namespace,
},
},
)
Expand Down Expand Up @@ -681,7 +686,7 @@ def get_object(self) -> objects.KubeadmControlPlaneTemplate:
"kind": objects.KubeadmControlPlaneTemplate.kind,
"metadata": {
"name": CLUSTER_CLASS_NAME,
"namespace": "magnum-system",
"namespace": self.namespace,
},
"spec": {
"template": {
Expand Down Expand Up @@ -796,7 +801,7 @@ def get_object(self) -> objects.KubeadmConfigTemplate:
"kind": objects.KubeadmConfigTemplate.kind,
"metadata": {
"name": CLUSTER_CLASS_NAME,
"namespace": "magnum-system",
"namespace": self.namespace,
},
"spec": {
"template": {
Expand Down Expand Up @@ -833,7 +838,7 @@ def get_object(self) -> objects.OpenStackMachineTemplate:
"kind": objects.OpenStackMachineTemplate.kind,
"metadata": {
"name": CLUSTER_CLASS_NAME,
"namespace": "magnum-system",
"namespace": self.namespace,
},
"spec": {
"template": {
Expand Down Expand Up @@ -862,7 +867,7 @@ def get_object(self) -> objects.OpenStackClusterTemplate:
"kind": objects.OpenStackClusterTemplate.kind,
"metadata": {
"name": CLUSTER_CLASS_NAME,
"namespace": "magnum-system",
"namespace": self.namespace,
},
"spec": {
"template": {
Expand Down Expand Up @@ -890,7 +895,7 @@ def get_object(self) -> objects.ClusterClass:
"kind": objects.ClusterClass.kind,
"metadata": {
"name": CLUSTER_CLASS_NAME,
"namespace": "magnum-system",
"namespace": self.namespace,
},
"spec": {
"controlPlane": {
Expand Down Expand Up @@ -1881,13 +1886,6 @@ def get_object(self) -> objects.ClusterClass:
"variable": "clusterIdentityRefName"
},
},
{
"op": "add",
"path": "/spec/template/spec/disableAPIServerFloatingIP",
"valueFrom": {
"variable": "disableAPIServerFloatingIP"
},
},
{
"op": "add",
"path": "/spec/template/spec/externalNetwork",
Expand All @@ -1903,6 +1901,30 @@ def get_object(self) -> objects.ClusterClass:
},
],
},
{
"name": "disableAPIServerFloatingIP",
"enabledIf": "{{ if .disableAPIServerFloatingIP }}true{{end}}",
"definitions": [
{
"selector": {
"apiVersion": objects.OpenStackClusterTemplate.version,
"kind": objects.OpenStackClusterTemplate.kind,
"matchResources": {
"infrastructureCluster": True,
},
},
"jsonPatches": [
{
"op": "add",
"path": "/spec/template/spec/disableAPIServerFloatingIP",
"valueFrom": {
"variable": "disableAPIServerFloatingIP"
},
},
],
},
],
},
{
"name": "controlPlaneAvailabilityZones",
"enabledIf": '{{ if ne (index .controlPlaneAvailabilityZones 0) "" }}true{{end}}',
Expand Down Expand Up @@ -2393,17 +2415,18 @@ def get_object(self) -> objects.ClusterClass:

def create_cluster_class(
api: pykube.HTTPClient,
namespace: str = "magnum-system",
) -> ClusterClass:
"""
Create a ClusterClass and all of it's supporting resources from a Magnum
cluster template using server-side apply.
"""

KubeadmControlPlaneTemplate(api).apply()
KubeadmConfigTemplate(api).apply()
OpenStackMachineTemplate(api).apply()
OpenStackClusterTemplate(api).apply()
ClusterClass(api).apply()
KubeadmControlPlaneTemplate(api, namespace).apply()
KubeadmConfigTemplate(api, namespace).apply()
OpenStackMachineTemplate(api, namespace).apply()
OpenStackClusterTemplate(api, namespace).apply()
ClusterClass(api, namespace).apply()


def mutate_machine_deployment(
Expand Down Expand Up @@ -2545,10 +2568,12 @@ def __init__(
context: context.RequestContext,
api: pykube.HTTPClient,
cluster: magnum_objects.Cluster,
namespace: str = "magnum-system",
):
self.context = context
self.api = api
self.cluster = cluster
self.namespace = namespace

@property
def labels(self) -> dict:
Expand All @@ -2567,7 +2592,7 @@ def labels(self) -> dict:
return {**super().labels, **labels}

def get_or_none(self) -> objects.Cluster:
return objects.Cluster.objects(self.api, namespace="magnum-system").get_or_none(
return objects.Cluster.objects(self.api, namespace=self.namespace).get_or_none(
name=self.cluster.stack_id
)

Expand All @@ -2593,7 +2618,7 @@ def get_object(self) -> objects.Cluster:
"kind": objects.Cluster.kind,
"metadata": {
"name": self.cluster.stack_id,
"namespace": "magnum-system",
"namespace": self.namespace,
"labels": self.labels,
},
"spec": {
Expand Down Expand Up @@ -2720,7 +2745,9 @@ def get_object(self) -> objects.Cluster:
"name": "cloudControllerManagerConfig",
"value": base64.encode_as_text(
utils.generate_cloud_controller_manager_config(
self.context, self.api, self.cluster
self.context,
self.api,
self.cluster,
)
),
},
Expand Down
Empty file.
125 changes: 125 additions & 0 deletions magnum_cluster_api/tests/functional/test_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Copyright (c) 2025 VEXXHOST, Inc.
# SPDX-License-Identifier: Apache-2.0

import string
from unittest import mock

import shortuuid
from magnum import objects as magnum_objects # type: ignore
from magnum.common import context as magnum_context # type: ignore
from magnum.tests.unit.db import utils # type: ignore
from oslo_utils import uuidutils # type: ignore
from oslotest import base # type: ignore
from tenacity import retry, retry_if_exception_type, stop_after_delay, wait_fixed

from magnum_cluster_api import clients, exceptions, resources


class TestClusterClass(base.BaseTestCase):
def setUp(self):
super(TestClusterClass, self).setUp()

self.api = clients.get_pykube_api()

alphabet = string.ascii_lowercase + string.digits
su = shortuuid.ShortUUID(alphabet=alphabet)
name = "test-%s" % (su.random(length=5))

self.namespace = resources.Namespace(self.api, name)
self.namespace.apply()
self.addCleanup(self.namespace.delete)

resources.create_cluster_class(self.api, namespace=self.namespace.name)

@mock.patch(
"magnum_cluster_api.clients.get_openstack_api",
)
@mock.patch("magnum.objects.nodegroup.NodeGroup.list")
@mock.patch(
"magnum_cluster_api.utils.generate_cloud_controller_manager_config",
return_value="fake-config",
)
@mock.patch(
"magnum_cluster_api.utils.get_image_uuid",
return_value=uuidutils.generate_uuid(),
)
@mock.patch(
"magnum_cluster_api.utils.ensure_controlplane_server_group",
return_value=uuidutils.generate_uuid(),
)
def _test_disable_api_server_floating_ip(
self,
mock_ensure_controlplane_server_group,
mock_get_image_uuid,
mock_generate_config,
mock_list,
mock_get_openstack_api,
**kwargs,
):
master_lb_floating_ip_enabled = kwargs.get("master_lb_floating_ip_enabled")
expected = kwargs.get("expected")

mock_get_openstack_api.return_value.cinder.return_value.volume_types.default.return_value.name = (
"fake-boot-volume-type"
)

context = magnum_context.RequestContext(is_admin=False)
cluster = magnum_objects.Cluster(
context,
**utils.get_test_cluster(
master_count=1,
master_flavor_id="m1.medium",
flavor_id="m1.large",
keypair="fake-keypair",
labels={},
),
)
cluster.cluster_template = magnum_objects.ClusterTemplate(
context,
**utils.get_test_cluster_template(),
)

if master_lb_floating_ip_enabled is not None:
cluster.labels["master_lb_floating_ip_enabled"] = str(
master_lb_floating_ip_enabled
)

capi_cluster = resources.Cluster(
context, self.api, cluster, namespace=self.namespace.name
)

capi_cluster_obj = capi_cluster.get_object()
for variable in capi_cluster_obj.obj["spec"]["topology"]["variables"]:
if variable["name"] == "master_lb_floating_ip_enabled":
self.assertEqual(expected, variable["value"])

capi_cluster.apply()
self.addCleanup(capi_cluster.delete)

@retry(
stop=stop_after_delay(10),
wait=wait_fixed(1),
retry=retry_if_exception_type(exceptions.OpenStackClusterNotCreated),
)
def get_capi_oc():
return capi_cluster_obj.openstack_cluster

capi_oc = get_capi_oc()
self.assertEqual(
expected, capi_oc.obj["spec"].get("disableAPIServerFloatingIP", False)
)

def test_disable_api_server_floating_ip_unset(self):
self._test_disable_api_server_floating_ip(
master_lb_floating_ip_enabled=None, expected=False
)

def test_disable_api_server_floating_ip_true(self):
self._test_disable_api_server_floating_ip(
master_lb_floating_ip_enabled=True, expected=False
)

def test_disable_api_server_floating_ip_false(self):
self._test_disable_api_server_floating_ip(
master_lb_floating_ip_enabled=False, expected=True
)
5 changes: 5 additions & 0 deletions magnum_cluster_api/tests/unit/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def test_generate_machine_deployments_for_cluster_with_deleting_node_group(
mock_get_image_uuid = mocker.patch("magnum_cluster_api.utils.get_image_uuid")
mock_get_image_uuid.return_value = "foo"

mock_ensure_worker_server_group = mocker.patch(
"magnum_cluster_api.utils.ensure_worker_server_group"
)
mock_ensure_worker_server_group.return_value = "foo"

mds = resources.generate_machine_deployments_for_cluster(
context,
cluster,
Expand Down
6 changes: 5 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ deps =
pytest
pytest-mock
responses
stestr

[testenv:{unit,py3,py38,py39,py310}]
commands =
pytest magnum_cluster_api/tests/unit/

[testenv:functional]
passenv =
KUBECONFIG
commands =
pytest magnum_cluster_api/tests/functional/
stestr --test-path=./magnum_cluster_api/tests/functional run {posargs}
stestr slowest

[testenv:linters]
skipsdist = True
Expand Down
2 changes: 2 additions & 0 deletions zuul.d/jobs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
pre-run: zuul.d/playbooks/functional/pre.yml
vars:
tox_envlist: functional
tox_environment:
KUBECONFIG: "{{ ansible_env.HOME }}/.kube/config"

- job:
name: magnum-cluster-api-image-build
Expand Down

0 comments on commit 0b0295b

Please sign in to comment.