Charmed-Kubernetes/flannel/tests/integration/test_flannel_integration.py

136 lines
4.8 KiB
Python

import json
import logging
import re
from ipaddress import ip_address, ip_network
from time import sleep
import pytest
from kubernetes import client
from kubernetes.config import load_kube_config_from_dict
log = logging.getLogger(__name__)
def _get_flannel_subnet_ip(unit):
"""Get subnet IP address."""
subnet = re.findall(r"[0-9]+(?:\.[0-9]+){3}", unit.workload_status_message)[0]
return ip_address(subnet)
async def _get_kubeconfig(model):
"""Get kubeconfig from kubernetes-master."""
unit = model.applications["kubernetes-master"].units[0]
action = await unit.run_action("get-kubeconfig")
output = await action.wait() # wait for result
return json.loads(output.data.get("results", {}).get("kubeconfig", "{}"))
async def _create_test_pod(model):
"""Create tests pod and return spec."""
# load kubernetes config
kubeconfig = await _get_kubeconfig(model)
load_kube_config_from_dict(kubeconfig)
api = client.CoreV1Api()
pod_manifest = {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {"name": "test"},
"spec": {
"containers": [
{"image": "busybox", "name": "test", "args": ["echo", "\"test\""]}
]
}
}
resp = api.create_namespaced_pod(body=pod_manifest, namespace="default")
# wait for pod not to be in pending
i = 0
while resp.status.phase == "Pending" and i < 30:
i += 1
sleep(10)
resp = api.read_namespaced_pod("test", namespace="default")
api.delete_namespaced_pod("test", namespace="default")
return resp
async def validate_flannel_cidr_network(ops_test):
"""Validate network CIDR assign to Flannel."""
flannel = ops_test.model.applications["flannel"]
flannel_config = await flannel.get_config()
cidr_network = ip_network(flannel_config.get("cidr", {}).get("value"))
for unit in flannel.units:
assert unit.workload_status == "active"
assert _get_flannel_subnet_ip(unit) in cidr_network
# create test pod
resp = await _create_test_pod(ops_test.model)
assert ip_address(resp.status.pod_ip) in cidr_network, \
"the new pod does not get the ip address in the cidr network"
@pytest.mark.abort_on_fail
async def test_build_and_deploy(ops_test, flannel_resource):
"""Build and deploy Flannel in bundle."""
flannel_charm = await ops_test.build_charm(".")
# Work around libjuju not handling local file resources by manually
# pre-deploying the charm w/ resource via the CLI. See
# https://github.com/juju/python-libjuju/issues/223
rc, stdout, stderr = await ops_test.run(
"juju",
"deploy",
"-m", ops_test.model_full_name,
flannel_charm,
"--resource", flannel_resource,
)
assert rc == 0, f"Failed to deploy with resource: {stderr or stdout}" # noqa: E999
bundle = ops_test.render_bundle(
"tests/data/bundle.yaml",
master_charm=flannel_charm,
series="focal",
# flannel_resource_name=flannel_resource_name, # This doesn't work currently
# flannel_resource=flannel_resource, # This doesn't work currently
)
await ops_test.model.deploy(bundle)
# This configuration is needed due testing on top of LXD containers.
# https://bugs.launchpad.net/charm-kubernetes-worker/+bug/1903566
await ops_test.model.applications["kubernetes-worker"].set_config({
"kubelet-extra-config": "{protectKernelDefaults: false}"
})
await ops_test.model.wait_for_idle(wait_for_active=True, timeout=60 * 60,
idle_period=60)
async def test_status_messages(ops_test):
"""Validate that the status messages are correct."""
await validate_flannel_cidr_network(ops_test)
async def test_change_cidr_network(ops_test):
"""Test configuration change."""
flannel = ops_test.model.applications["flannel"]
await flannel.set_config({"cidr": "10.2.0.0/16"})
rc, stdout, stderr = await ops_test.run(
"juju", "run", "-m", ops_test.model_full_name, "--application", "flannel",
"--", "hooks/config-changed"
)
assert rc == 0, f"Failed to run hook with resource: {stderr or stdout}"
# note (rgildein): There is need to restart kubernetes-worker machine.
# https://bugs.launchpad.net/charm-flannel/+bug/1932551
k8s_worker = ops_test.model.applications["kubernetes-worker"].units[0]
rc, stdout, stderr = await ops_test.run(
"juju", "ssh", "-m", ops_test.model_full_name, f"{k8s_worker.name}",
"--", "sudo reboot now"
)
assert rc in [0, 255], (f"Failed to restart kubernetes-worker with "
f"resource: {stderr or stdout}")
await ops_test.model.wait_for_idle(wait_for_active=True, idle_period=60)
await validate_flannel_cidr_network(ops_test)