136 lines
4.8 KiB
Python
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)
|