Skip to content

v5.16.0 #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,21 @@ jobs:
run: |
timestamp=$(date +'%Y%m%d%H%M')
report_filename="${timestamp}_sdk_test_report.xml"
status=0
if ! python3 -m pytest test/integration/${INTEGRATION_TEST_PATH} --disable-warnings --junitxml="${report_filename}"; then
echo "EXIT_STATUS=1" >> $GITHUB_ENV
fi
make testint TEST_ARGS="--junitxml=${report_filename}"
env:
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}

- name: Add additional information to XML report
- name: Upload test results
if: always()
run: |
filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python tod_scripts/add_to_xml_test_report.py \
--branch_name "${GITHUB_REF#refs/*/}" \
--gha_run_id "$GITHUB_RUN_ID" \
--gha_run_number "$GITHUB_RUN_NUMBER" \
--xmlfile "${filename}"

- name: Upload test results
run: |
report_filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python3 tod_scripts/test_report_upload_script.py "${report_filename}"
sync
python3 tod_scripts/test_report_upload_script.py "${filename}"
env:
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }}
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }}

- name: Test Execution Status Handler
run: |
if [[ "$EXIT_STATUS" != 0 ]]; then
echo "Test execution contains failure(s)"
exit $EXIT_STATUS
else
echo "Tests passed!"
fi
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.8.10
linode_api4-python
16 changes: 10 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
PYTHON ?= python3

INTEGRATION_TEST_PATH :=
TEST_CASE_COMMAND :=
MODEL_COMMAND :=
TEST_SUITE :=
TEST_ARGS :=

LINODE_SDK_VERSION ?= "0.0.0.dev"
VERSION_MODULE_DOCSTRING ?= \"\"\"\nThe version of this linode_api4 package.\n\"\"\"\n\n
VERSION_FILE := ./linode_api4/version.py

ifdef TEST_CASE
TEST_CASE_COMMAND = -k $(TEST_CASE)
TEST_CASE_COMMAND = -k $(TEST_CASE)
endif

ifdef TEST_MODEL
MODEL_COMMAND = models/$(TEST_MODEL)
ifdef TEST_SUITE
ifneq ($(TEST_SUITE),linode_client)
TEST_COMMAND = models/$(TEST_SUITE)
else
TEST_COMMAND = linode_client
endif
endif

.PHONY: clean
Expand Down Expand Up @@ -67,7 +71,7 @@ lint: build

.PHONY: testint
testint:
$(PYTHON) -m pytest test/integration/${INTEGRATION_TEST_PATH}${MODEL_COMMAND} ${TEST_CASE_COMMAND}
$(PYTHON) -m pytest test/integration/${TEST_COMMAND} ${TEST_CASE_COMMAND} ${TEST_ARGS}

.PHONY: testunit
testunit:
Expand Down
9 changes: 3 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,10 @@ Run the tests locally using the make command. Run the entire test suite using co

make testint

To run a specific package, use environment variable `INTEGRATION_TEST_PATH` with `testint` command::
To run a specific package/suite, use the environment variable `TEST_SUITE` using directory names in `integration/...` folder ::

make INTEGRATION_TEST_PATH="linode_client" testint

To run a specific model test suite, set the environment variable `TEST_MODEL` using file name in `integration/models`::

make TEST_MODEL="test_account.py" testint
make TEST_SUITE="account" testint // Runs tests in `integration/models/account` directory
make TEST_SUITE="linode_client" testint // Runs tests in `integration/linode_client` directory

Lastly to run a specific test case use environment variable `TEST_CASE` with `testint` command::

Expand Down
32 changes: 29 additions & 3 deletions linode_api4/groups/lke.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from typing import Any, Dict, Union

from linode_api4.errors import UnexpectedResponseError
from linode_api4.groups import Group
from linode_api4.objects import Base, KubeVersion, LKECluster
from linode_api4.objects import (
Base,
JSONObject,
KubeVersion,
LKECluster,
LKEClusterControlPlaneOptions,
drop_null_keys,
)


class LKEGroup(Group):
Expand Down Expand Up @@ -47,7 +56,17 @@ def clusters(self, *filters):
"""
return self.client._get_and_filter(LKECluster, *filters)

def cluster_create(self, region, label, node_pools, kube_version, **kwargs):
def cluster_create(
self,
region,
label,
node_pools,
kube_version,
control_plane: Union[
LKEClusterControlPlaneOptions, Dict[str, Any]
] = None,
**kwargs,
):
"""
Creates an :any:`LKECluster` on this account in the given region, with
the given label, and with node pools as described. For example::
Expand Down Expand Up @@ -80,6 +99,8 @@ def cluster_create(self, region, label, node_pools, kube_version, **kwargs):
formatted dicts.
:param kube_version: The version of Kubernetes to use
:type kube_version: KubeVersion or str
:param control_plane: Dict[str, Any] or LKEClusterControlPlaneRequest
:type control_plane: The control plane configuration of this LKE cluster.
:param kwargs: Any other arguments to pass along to the API. See the API
docs for possible values.

Expand Down Expand Up @@ -112,10 +133,15 @@ def cluster_create(self, region, label, node_pools, kube_version, **kwargs):
if issubclass(type(kube_version), Base)
else kube_version
),
"control_plane": (
control_plane.dict
if issubclass(type(control_plane), JSONObject)
else control_plane
),
}
params.update(kwargs)

result = self.client.post("/lke/clusters", data=params)
result = self.client.post("/lke/clusters", data=drop_null_keys(params))

if "id" not in result:
raise UnexpectedResponseError(
Expand Down
138 changes: 138 additions & 0 deletions linode_api4/objects/lke.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, Union
from urllib import parse

from linode_api4.errors import UnexpectedResponseError
from linode_api4.objects import (
Base,
DerivedBase,
Instance,
JSONObject,
MappedObject,
Property,
Region,
Expand All @@ -26,6 +29,61 @@ class KubeVersion(Base):
}


@dataclass
class LKEClusterControlPlaneACLAddressesOptions(JSONObject):
"""
LKEClusterControlPlaneACLAddressesOptions are options used to configure
IP ranges that are explicitly allowed to access an LKE cluster's control plane.
"""

ipv4: Optional[List[str]] = None
ipv6: Optional[List[str]] = None


@dataclass
class LKEClusterControlPlaneACLOptions(JSONObject):
"""
LKEClusterControlPlaneACLOptions is used to set
the ACL configuration of an LKE cluster's control plane.
"""

enabled: Optional[bool] = None
addresses: Optional[LKEClusterControlPlaneACLAddressesOptions] = None


@dataclass
class LKEClusterControlPlaneOptions(JSONObject):
"""
LKEClusterControlPlaneOptions is used to configure
the control plane of an LKE cluster during its creation.
"""

high_availability: Optional[bool] = None
acl: Optional[LKEClusterControlPlaneACLOptions] = None


@dataclass
class LKEClusterControlPlaneACLAddresses(JSONObject):
"""
LKEClusterControlPlaneACLAddresses describes IP ranges that are explicitly allowed
to access an LKE cluster's control plane.
"""

ipv4: List[str] = None
ipv6: List[str] = None


@dataclass
class LKEClusterControlPlaneACL(JSONObject):
"""
LKEClusterControlPlaneACL describes the ACL configuration of an LKE cluster's
control plane.
"""

enabled: bool = False
addresses: LKEClusterControlPlaneACLAddresses = None


class LKENodePoolNode:
"""
AN LKE Node Pool Node is a helper class that is used to populate the "nodes"
Expand Down Expand Up @@ -129,6 +187,21 @@ class LKECluster(Base):
"control_plane": Property(mutable=True),
}

def invalidate(self):
"""
Extends the default invalidation logic to drop cached properties.
"""
if hasattr(self, "_api_endpoints"):
del self._api_endpoints

if hasattr(self, "_kubeconfig"):
del self._kubeconfig

if hasattr(self, "_control_plane_acl"):
del self._control_plane_acl

Base.invalidate(self)

@property
def api_endpoints(self):
"""
Expand Down Expand Up @@ -186,6 +259,26 @@ def kubeconfig(self):

return self._kubeconfig

@property
def control_plane_acl(self) -> LKEClusterControlPlaneACL:
"""
Gets the ACL configuration of this cluster's control plane.

API Documentation: TODO

:returns: The cluster's control plane ACL configuration.
:rtype: LKEClusterControlPlaneACL
"""

if not hasattr(self, "_control_plane_acl"):
result = self._client.get(
f"{LKECluster.api_endpoint}/control_plane_acl", model=self
)

self._control_plane_acl = result.get("acl")

return LKEClusterControlPlaneACL.from_json(self._control_plane_acl)

def node_pool_create(self, node_type, node_count, **kwargs):
"""
Creates a new :any:`LKENodePool` for this cluster.
Expand Down Expand Up @@ -335,3 +428,48 @@ def service_token_delete(self):
self._client.delete(
"{}/servicetoken".format(LKECluster.api_endpoint), model=self
)

def control_plane_acl_update(
self, acl: Union[LKEClusterControlPlaneACLOptions, Dict[str, Any]]
) -> LKEClusterControlPlaneACL:
"""
Updates the ACL configuration for this cluster's control plane.

API Documentation: TODO

:param acl: The ACL configuration to apply to this cluster.
:type acl: LKEClusterControlPlaneACLOptions or Dict[str, Any]

:returns: The updated control plane ACL configuration.
:rtype: LKEClusterControlPlaneACL
"""
if isinstance(acl, LKEClusterControlPlaneACLOptions):
acl = acl.dict

result = self._client.put(
f"{LKECluster.api_endpoint}/control_plane_acl",
model=self,
data={"acl": acl},
)

acl = result.get("acl")

self._control_plane_acl = result.get("acl")

return LKEClusterControlPlaneACL.from_json(acl)

def control_plane_acl_delete(self):
"""
Deletes the ACL configuration for this cluster's control plane.
This has the same effect as calling control_plane_acl_update with the `enabled` field
set to False. Access controls are disabled and all rules are deleted.

API Documentation: TODO
"""
self._client.delete(
f"{LKECluster.api_endpoint}/control_plane_acl", model=self
)

# Invalidate the cache so it is automatically refreshed on next access
if hasattr(self, "_control_plane_acl"):
del self._control_plane_acl
Loading