From 87054c67786e5397849fa5df2d863daf1caa93c2 Mon Sep 17 00:00:00 2001 From: Jamie Wiebe Date: Mon, 2 May 2022 14:23:37 +0200 Subject: [PATCH] add v1 model and tests for poddisruptionbudgets --- k8s/models/policy_v1_pod_disruption_budget.py | 50 ++++++++++ .../test_policy_v1_pod_disruption_budget.py | 99 +++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 k8s/models/policy_v1_pod_disruption_budget.py create mode 100644 tests/k8s/test_policy_v1_pod_disruption_budget.py diff --git a/k8s/models/policy_v1_pod_disruption_budget.py b/k8s/models/policy_v1_pod_disruption_budget.py new file mode 100644 index 0000000..6e611a9 --- /dev/null +++ b/k8s/models/policy_v1_pod_disruption_budget.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 + +# Copyright 2017-2019 The FIAAS Authors +# +# 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 __future__ import absolute_import + +import six + +from .common import ObjectMeta +from ..base import Model +from ..fields import Field, ListField + + +class LabelSelectorRequirement(Model): + key = Field(six.text_type) + operator = Field(six.text_type) + values = ListField(six.text_type) + + +class LabelSelector(Model): + matchExpressions = Field(LabelSelectorRequirement) + matchLabels = Field(dict) + + +class PodDisruptionBudgetSpec(Model): + minAvailable = Field(six.text_type, alt_type=int) + maxUnavailable = Field(six.text_type, alt_type=int) + selector = Field(LabelSelector) + + +class PodDisruptionBudget(Model): + class Meta: + list_url = "/apis/policy/v1/poddisruptionbudgets" + url_template = "/apis/policy/v1/namespaces/{namespace}/poddisruptionbudgets/{name}" + + metadata = Field(ObjectMeta) + spec = Field(PodDisruptionBudgetSpec) diff --git a/tests/k8s/test_policy_v1_pod_disruption_budget.py b/tests/k8s/test_policy_v1_pod_disruption_budget.py new file mode 100644 index 0000000..c4968d2 --- /dev/null +++ b/tests/k8s/test_policy_v1_pod_disruption_budget.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 + +# Copyright 2017-2019 The FIAAS Authors +# +# 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. + + +import mock +import pytest + +from k8s.client import NotFound +from k8s.models.common import ObjectMeta +from k8s.models.pod_disruption_budget import PodDisruptionBudget, PodDisruptionBudgetSpec, LabelSelector + +NAME = "my-pod-disruption-budget" +NAMESPACE = "my-namespace" + + +@pytest.mark.usefixtures("k8s_config") +class TestPodDisruptionBudget(object): + def test_created_if_not_exists(self, post, api_get): + api_get.side_effect = NotFound() + pdb = _create_default_pdb() + call_params = pdb.as_dict() + post.return_value.json.return_value = call_params + + assert pdb._new + pdb.save() + assert not pdb._new + + pytest.helpers.assert_any_call(post, _uri(NAMESPACE), call_params) + + def test_updated_if_exists(self, get, put): + mock_response = _create_mock_response() + get.return_value = mock_response + pdb = _create_default_pdb() + + from_api = PodDisruptionBudget.get_or_create( + metadata=pdb.metadata, + spec=pdb.spec, + ) + assert not from_api._new + assert from_api.spec == pdb.spec + + def test_deleted(self, delete): + PodDisruptionBudget.delete(NAME, namespace=NAMESPACE) + pytest.helpers.assert_any_call(delete, _uri(NAMESPACE, NAME)) + + +def _create_mock_response(): + mock_response = mock.Mock() + mock_response.json.return_value = { + "apiVersion": "policy/v1", + "kind": "PodDisruptionBudget", + "metadata": { + "creationTimestamp": "2017-09-08T13:37:00Z", + "generation": 1, + "labels": { + "test": "true" + }, + "name": NAME, + "namespace": NAMESPACE, + "resourceVersion": "42", + "selfLink": _uri(NAMESPACE, NAME), + "uid": "d8f1ba26-b182-11e6-a364-fa163ea2a9c4" + }, + "spec": { + "minAvailable": 1, + "selector": { + "matchLabels": { + "application": "my-app", + }, + }, + }, + } + return mock_response + + +def _create_default_pdb(): + object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) + selector = LabelSelector(matchLabels={"app": "my-app"}) + spec = PodDisruptionBudgetSpec(maxUnavailable=1, selector=selector) + return PodDisruptionBudget(metadata=object_meta, spec=spec) + + +def _uri(namespace, name=""): + uri = "/apis/policy/v1/namespaces/{namespace}/poddisruptionbudgets/{name}" + return uri.format(name=name, namespace=namespace)