Skip to content

Commit

Permalink
Fix versions of ingresses in ready_check method (#191)
Browse files Browse the repository at this point in the history
  • Loading branch information
herodes1991 authored Nov 7, 2022
1 parent bb251d6 commit 727967d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 129 deletions.
5 changes: 3 additions & 2 deletions fiaas_deploy_daemon/deployer/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ class Deployer(DaemonThread):
Mainly focused on bookkeeping, and leaving the hard work to the framework-adapter.
"""

def __init__(self, deploy_queue, bookkeeper, adapter, scheduler, lifecycle, config):
def __init__(self, deploy_queue, bookkeeper, adapter, scheduler, lifecycle, ingress_adapter, config):
super(Deployer, self).__init__()
self._queue = _make_gen(deploy_queue.get)
self._bookkeeper = bookkeeper
self._adapter = adapter
self._scheduler = scheduler
self._lifecycle = lifecycle
self._ingress_adapter = ingress_adapter
self._config = config

def __call__(self):
Expand All @@ -59,7 +60,7 @@ def _update(self, app_spec, lifecycle_subject):
self._adapter.deploy(app_spec)
if app_spec.name != "fiaas-deploy-daemon":
self._scheduler.add(ReadyCheck(app_spec, self._bookkeeper, self._lifecycle, lifecycle_subject,
self._config))
self._ingress_adapter, self._config))
else:
self._lifecycle.success(lifecycle_subject)
self._bookkeeper.success(app_spec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ def delete_list(self, app_spec):
except NotFound:
pass

def find(self, name, namespace):
return Ingress.find(name, namespace)

def _make_http_ingress_rule_value(self, app_spec, pathmappings):
http_ingress_paths = [
HTTPIngressPath(
Expand Down
3 changes: 3 additions & 0 deletions fiaas_deploy_daemon/deployer/kubernetes/ingress_v1beta1.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def delete_list(self, app_spec):
except NotFound:
pass

def find(self, name, namespace):
return Ingress.find(name, namespace)

def _make_http_ingress_rule_value(self, app_spec, pathmappings):
http_ingress_paths = [
HTTPIngressPath(path=pm.path, backend=IngressBackend(serviceName=app_spec.name, servicePort=pm.port))
Expand Down
6 changes: 3 additions & 3 deletions fiaas_deploy_daemon/deployer/kubernetes/ready_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
from k8s.client import NotFound
from k8s.models.certificate import Certificate
from k8s.models.deployment import Deployment
from k8s.models.ingress import Ingress
from monotonic import monotonic as time_monotonic

LOG = logging.getLogger(__name__)


class ReadyCheck(object):
def __init__(self, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
def __init__(self, app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config):
self._app_spec = app_spec
self._bookkeeper = bookkeeper
self._lifecycle = lifecycle
Expand All @@ -41,6 +40,7 @@ def __init__(self, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
)
self._fail_after = time_monotonic() + self._fail_after_seconds
self._should_check_ingress = config.tls_certificate_ready
self._ingress_adapter = ingress_adapter

def __call__(self):
if self._ready():
Expand Down Expand Up @@ -77,7 +77,7 @@ def _is_certificate_ready(self, cert):

def _ingress_ready(self):
try:
ing_list = Ingress.find(self._app_spec.name, self._app_spec.namespace)
ing_list = self._ingress_adapter.find(self._app_spec.name, self._app_spec.namespace)
except NotFound:
return False

Expand Down
185 changes: 65 additions & 120 deletions tests/fiaas_deploy_daemon/deployer/kubernetes/test_ready_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@
from monotonic import monotonic as time_monotonic

from fiaas_deploy_daemon.deployer.bookkeeper import Bookkeeper
from fiaas_deploy_daemon.deployer.kubernetes.ingress_v1beta1 import V1Beta1IngressAdapter
from fiaas_deploy_daemon.config import Configuration
from fiaas_deploy_daemon.deployer.kubernetes.ready_check import ReadyCheck
from fiaas_deploy_daemon.lifecycle import Lifecycle, Subject
from fiaas_deploy_daemon.specs.models import LabelAndAnnotationSpec, IngressTLSSpec
from k8s.models.certificate import Certificate, CertificateCondition
from k8s.models.ingress import Ingress, IngressTLS
from k8s.models.networking_v1_ingress import Ingress as V1Ingress, IngressTLS as V1IngressTLS

REPLICAS = 2

Expand All @@ -49,14 +51,23 @@ def lifecycle_subject(self, app_spec):
def config(self):
return Configuration([])

@pytest.fixture
def ingress_adapter(self):
return mock.create_autospec(V1Beta1IngressAdapter)

@pytest.fixture
def get_cert(self):
with mock.patch("k8s.models.certificate.Certificate.get") as get_cert:
yield get_cert

@pytest.mark.parametrize("generation,observed_generation", (
(0, 0),
(0, 1)
))
def test_deployment_complete(self, get, app_spec, bookkeeper, generation, observed_generation, lifecycle,
lifecycle_subject, config):
lifecycle_subject, ingress_adapter, config):
self._create_response(get, generation=generation, observed_generation=observed_generation)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)

assert ready() is False
bookkeeper.success.assert_called_with(app_spec)
Expand All @@ -73,9 +84,10 @@ def test_deployment_complete(self, get, app_spec, bookkeeper, generation, observ
(2, 2, 2, 2, 1, 0),
))
def test_deployment_incomplete(self, get, app_spec, bookkeeper, requested, replicas, available, updated,
generation, observed_generation, lifecycle, lifecycle_subject, config):
generation, observed_generation, lifecycle, lifecycle_subject, ingress_adapter,
config):
self._create_response(get, requested, replicas, available, updated, generation, observed_generation)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)

assert ready() is True
bookkeeper.success.assert_not_called()
Expand All @@ -91,13 +103,13 @@ def test_deployment_incomplete(self, get, app_spec, bookkeeper, requested, repli
(2, 1, 1, 1, {"fiaas/source-repository": "xyz"}, "xyz"),
))
def test_deployment_failed(self, get, app_spec, bookkeeper, requested, replicas, available, updated,
lifecycle, lifecycle_subject, annotations, repository, config):
lifecycle, lifecycle_subject, annotations, repository, ingress_adapter, config):
if annotations:
app_spec = app_spec._replace(annotations=LabelAndAnnotationSpec(*[annotations] * 7))

self._create_response(get, requested, replicas, available, updated)

ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)
ready._fail_after = time_monotonic()

assert ready() is False
Expand All @@ -106,136 +118,69 @@ def test_deployment_failed(self, get, app_spec, bookkeeper, requested, replicas,
lifecycle.success.assert_not_called()
lifecycle.failed.assert_called_with(lifecycle_subject)

def test_deployment_complete_deactivated(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
def test_deployment_complete_deactivated(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject,
ingress_adapter, config):

self._create_response_zero_replicas(get)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)

assert ready() is False
bookkeeper.success.assert_called_with(app_spec)
bookkeeper.failed.assert_not_called()
lifecycle.success.assert_called_with(lifecycle_subject)
lifecycle.failed.assert_not_called()

def test_tls_ingress_ready(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
config.tls_certificate_ready = True
app_spec = app_spec._replace(ingress_tls=IngressTLSSpec(enabled=True, certificate_issuer=None))
replicas = 2

with mock.patch("k8s.models.ingress.Ingress.find") as find:
ingress = mock.create_autospec(Ingress, spec_set=True)
ingress.spec.tls = [IngressTLS(hosts=["extra1.example.com"], secretName="secret1")]
find.return_value = [ingress]

with mock.patch("k8s.models.certificate.Certificate.get") as get_crd:
expiration_date = datetime.now() + timedelta(days=5)
get_crd.return_value = self._mock_certificate(True, expiration_date)

self._create_response(get, replicas, replicas, replicas, replicas)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)

assert ready() is False
bookkeeper.success.assert_called_with(app_spec)
bookkeeper.failed.assert_not_called()
lifecycle.success.assert_called_with(lifecycle_subject)
lifecycle.failed.assert_not_called()

def test_tls_ingress_ready_null_notafter(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
config.tls_certificate_ready = True
app_spec = app_spec._replace(ingress_tls=IngressTLSSpec(enabled=True, certificate_issuer=None))
replicas = 2

with mock.patch("k8s.models.ingress.Ingress.find") as find:
ingress = mock.create_autospec(Ingress, spec_set=True)
ingress.spec.tls = [IngressTLS(hosts=["extra1.example.com"], secretName="secret1")]
find.return_value = [ingress]

with mock.patch("k8s.models.certificate.Certificate.get") as get_crd:
get_crd.return_value = self._mock_certificate(True)

self._create_response(get, replicas, replicas, replicas, replicas)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)

assert ready() is False
bookkeeper.success.assert_called_with(app_spec)
bookkeeper.failed.assert_not_called()
lifecycle.success.assert_called_with(lifecycle_subject)
lifecycle.failed.assert_not_called()

def test_tls_ingress_ready_expired_certificate(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
config.tls_certificate_ready = True
app_spec = app_spec._replace(ingress_tls=IngressTLSSpec(enabled=True, certificate_issuer=None))
replicas = 2

with mock.patch("k8s.models.ingress.Ingress.find") as find:
ingress = mock.create_autospec(Ingress, spec_set=True)
ingress.spec.tls = [IngressTLS(hosts=["extra1.example.com"], secretName="secret1")]
find.return_value = [ingress]

with mock.patch("k8s.models.certificate.Certificate.get") as get_crd:
expiration_date = datetime.now() - timedelta(days=5)
get_crd.return_value = self._mock_certificate(True, expiration_date)

self._create_response(get, replicas, replicas, replicas, replicas)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready._fail_after = time_monotonic()

assert ready() is False
bookkeeper.failed.assert_called_with(app_spec)
bookkeeper.success.assert_not_called()
lifecycle.failed.assert_called_with(lifecycle_subject)
lifecycle.success.assert_not_called()

def test_tls_ingress_not_ready_timeout(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
config.tls_certificate_ready = True
app_spec = app_spec._replace(ingress_tls=IngressTLSSpec(enabled=True, certificate_issuer=None))
replicas = 2

with mock.patch("k8s.models.ingress.Ingress.find") as find:
ingress = mock.create_autospec(Ingress)
ingress.spec.tls = [IngressTLS(hosts=["extra1.example.com"], secretName="secret1")]
find.return_value = [ingress]

with mock.patch("k8s.models.certificate.Certificate.get") as get_crd:
get_crd.return_value = self._mock_certificate(False)

self._create_response(get, replicas, replicas, replicas, replicas)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready._fail_after = time_monotonic()

assert ready() is False
bookkeeper.failed.assert_called_with(app_spec)
bookkeeper.success.assert_not_called()
lifecycle.failed.assert_called_with(lifecycle_subject)
lifecycle.success.assert_not_called()

def test_tls_ingress_not_ready(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, config):
@pytest.mark.parametrize("ingress_class,ingress_tls,cert_valid,expiration_date,result,success", (
(Ingress, IngressTLS, True, (datetime.now() + timedelta(days=5)), False, True),
(V1Ingress, V1IngressTLS, True, (datetime.now() + timedelta(days=5)), False, True),
(Ingress, IngressTLS, True, None, False, True),
(V1Ingress, V1IngressTLS, True, None, False, True),
(Ingress, IngressTLS, True, (datetime.now() - timedelta(days=5)), False, False),
(V1Ingress, V1IngressTLS, True, (datetime.now() - timedelta(days=5)), False, False),
(Ingress, IngressTLS, False, None, False, False),
(V1Ingress, V1IngressTLS, False, None, False, False),
(Ingress, IngressTLS, False, None, True, True),
(V1Ingress, V1IngressTLS, False, None, True, True)
))
def test_tls_ingress(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject, get_cert, ingress_adapter,
ingress_class, ingress_tls, cert_valid, expiration_date, result, success, config):
config.tls_certificate_ready = True
app_spec = app_spec._replace(ingress_tls=IngressTLSSpec(enabled=True, certificate_issuer=None))
replicas = 2

with mock.patch("k8s.models.ingress.Ingress.find") as find:
ingress = mock.create_autospec(Ingress)
ingress.spec.tls = [IngressTLS(hosts=["extra1.example.com"], secretName="secret1")]
find.return_value = [ingress]

with mock.patch("k8s.models.certificate.Certificate.get") as get_crd:
get_crd.return_value = self._mock_certificate(False)

self._create_response(get, replicas, replicas, replicas, replicas)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)

assert ready() is True
bookkeeper.failed.assert_not_called()
bookkeeper.success.assert_not_called()
lifecycle.failed.assert_not_called()
lifecycle.success.assert_not_called()
ingress = mock.create_autospec(ingress_class, spec_set=True)
ingress.spec.tls = [ingress_tls(hosts=["extra1.example.com"], secretName="secret1")]
ingress_adapter.find.return_value = [ingress]

get_cert.return_value = self._mock_certificate(cert_valid, expiration_date)
self._create_response(get, replicas, replicas, replicas, replicas)

ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)
if not success:
ready._fail_after = time_monotonic()

assert ready() is result
if result:
bookkeeper.success.assert_not_called()
lifecycle.success.assert_not_called()
bookkeeper.failed.assert_not_called()
lifecycle.failed.assert_not_called()
elif success:
bookkeeper.success.assert_called_with(app_spec)
lifecycle.success.assert_called_with(lifecycle_subject)
bookkeeper.failed.assert_not_called()
lifecycle.failed.assert_not_called()
else:
bookkeeper.success.assert_not_called()
lifecycle.success.assert_not_called()
bookkeeper.failed.assert_called_with(app_spec)
lifecycle.failed.assert_called_with(lifecycle_subject)

def test_deployment_tls_config_no_tls_extension(self, get, app_spec, bookkeeper, lifecycle,
lifecycle_subject, config):
def test_deployment_tls_config_no_tls_extension(self, get, app_spec, bookkeeper, lifecycle, lifecycle_subject,
ingress_adapter, config):
config.tls_certificate_ready = True
self._create_response(get)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config)
ready = ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter, config)

assert ready() is False
bookkeeper.success.assert_called_with(app_spec)
Expand Down
14 changes: 10 additions & 4 deletions tests/fiaas_deploy_daemon/deployer/test_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from fiaas_deploy_daemon.deployer.bookkeeper import Bookkeeper
from fiaas_deploy_daemon.deployer.deploy import Deployer
from fiaas_deploy_daemon.deployer.kubernetes.adapter import K8s
from fiaas_deploy_daemon.deployer.kubernetes.ingress_v1beta1 import V1Beta1IngressAdapter
from fiaas_deploy_daemon.deployer.kubernetes.ready_check import ReadyCheck
from fiaas_deploy_daemon.deployer.scheduler import Scheduler
from fiaas_deploy_daemon.lifecycle import Lifecycle, Subject, STATUS_STARTED, STATUS_FAILED
Expand Down Expand Up @@ -54,13 +55,17 @@ def lifecycle_subject(self, app_spec):
return Subject(app_spec.uid, app_spec.name, app_spec.namespace, app_spec.deployment_id, None,
app_spec.labels.status, app_spec.annotations.status)

@pytest.fixture
def ingress_adapter(self):
return mock.create_autospec(V1Beta1IngressAdapter, spec_set=True)

@pytest.fixture
def config(self):
return Configuration([])

@pytest.fixture
def deployer(self, app_spec, bookkeeper, adapter, scheduler, lifecycle, lifecycle_subject, config):
deployer = Deployer(Queue(), bookkeeper, adapter, scheduler, lifecycle, config)
def deployer(self, app_spec, bookkeeper, adapter, scheduler, lifecycle, lifecycle_subject, ingress_adapter, config):
deployer = Deployer(Queue(), bookkeeper, adapter, scheduler, lifecycle, ingress_adapter, config)
deployer._queue = [DeployerEvent("UPDATE", app_spec, lifecycle_subject)]
return deployer

Expand Down Expand Up @@ -96,8 +101,9 @@ def test_signals_failure_on_exception(self, app_spec, lifecycle, lifecycle_subje
lifecycle.state_change_signal.send.assert_called_with(status=STATUS_FAILED, subject=lifecycle_subject)

def test_schedules_ready_check(self, app_spec, scheduler, bookkeeper, deployer, lifecycle, lifecycle_subject,
config):
ingress_adapter, config):
deployer()

lifecycle.state_change_signal.send.assert_called_once_with(status=STATUS_STARTED, subject=lifecycle_subject)
scheduler.add.assert_called_with(ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, config))
scheduler.add.assert_called_with(ReadyCheck(app_spec, bookkeeper, lifecycle, lifecycle_subject, ingress_adapter,
config))

0 comments on commit 727967d

Please sign in to comment.