async def kubernetes(ops_test): kubeconfig_path = ops_test.tmp_path / "kubeconfig" retcode, stdout, stderr = await ops_test.run( "juju", "scp", "-m", ops_test.model_full_name, "kubernetes-control-plane/leader:config", kubeconfig_path, ) if retcode != 0: log.error(f"retcode: {retcode}") log.error(f"stdout:\n{stdout.strip()}") log.error(f"stderr:\n{stderr.strip()}") pytest.fail("Failed to copy kubeconfig from kubernetes-control-plane") namespace = ( "test-kubernetes-control-plane-integration-" + random.choice(string.ascii_lowercase + string.digits) * 5 ) config = KubeConfig.from_file(kubeconfig_path) kubernetes = Client( config=config.get(context_name="juju-context"), namespace=namespace, trust_env=False, ) namespace_obj = Namespace(metadata=ObjectMeta(name=namespace)) kubernetes.create(namespace_obj) yield kubernetes kubernetes.delete(Namespace, namespace)
async def test_seldon_deployment(ops_test: OpsTest): namespace = ops_test.model_name client = Client() this_ns = client.get(res=Namespace, name=namespace) this_ns.metadata.labels.update({"serving.kubeflow.org/inferenceservice": "enabled"}) client.patch(res=Namespace, name=this_ns.metadata.name, obj=this_ns) SeldonDeployment = create_namespaced_resource( group="machinelearning.seldon.io", version="v1", kind="seldondeployment", plural="seldondeployments", verbs=None, ) with open("examples/serve-simple-v1.yaml") as f: sdep = SeldonDeployment(yaml.safe_load(f.read())) client.create(sdep, namespace=namespace) for i in range(30): dep = client.get(SeldonDeployment, "seldon-model", namespace=namespace) state = dep.get("status", {}).get("state") if state == "Available": logger.info(f"SeldonDeployment status == {state}") break else: logger.info(f"SeldonDeployment status == {state} (waiting for 'Available')") time.sleep(5) else: pytest.fail("Waited too long for seldondeployment/seldon-model!") service_name = "seldon-model-example-classifier" service = client.get(Service, name=service_name, namespace=namespace) service_ip = service.spec.clusterIP service_port = next(p for p in service.spec.ports if p.name == "http").port response = requests.post( f"http://{service_ip}:{service_port}/predict", json={ "data": { "names": ["a", "b"], "tensor": {"shape": [2, 2], "values": [0, 0, 1, 1]}, } }, ) response.raise_for_status() response = response.json() assert response["data"]["names"] == ["proba"] assert response["data"]["tensor"]["shape"] == [2, 1] assert response["meta"] == {}
def test_pod_already_exist(obj_name): client = Client() client.create(create_pod(obj_name, "sleep 5")) try: with pytest.raises(ApiError) as exc_info: client.create(create_pod(obj_name, "sleep 5")) status = exc_info.value.status assert status.code == 409 assert status.reason == 'AlreadyExists' assert status.status == 'Failure' finally: # delete the pod client.delete(Pod, obj_name)
def set_manifest(manifest): client = Client() errors = [] for resource in manifest: try: client.create(resource) except ApiError as err: if err.status.reason == "AlreadyExists": client.patch(type(resource), resource.metadata.name, resource) else: errors.append(err) return errors
def test_pod_apis(obj_name): client = Client() # list kube-system namespace pods = [pod.metadata.name for pod in client.list(Pod, namespace='kube-system')] assert len(pods) > 0 assert any(name.startswith('metrics-server') for name in pods) # create a pod pod = client.create(create_pod(obj_name, "while true;do echo 'this is a test';sleep 5; done")) try: assert pod.metadata.name == obj_name assert pod.metadata.namespace == client.namespace assert pod.status.phase wait_pod(client, pod) # read pod logs for l in client.log(obj_name, follow=True): assert l == 'this is a test\n' break finally: # delete the pod client.delete(Pod, obj_name)
def test_namespaced_methods(obj_name): client = Client() config = ConfigMap( metadata=ObjectMeta(name=obj_name, namespace='default'), data={'key1': 'value1', 'key2': 'value2'} ) # create config = client.create(config) try: assert config.metadata.name == obj_name assert config.data['key1'] == 'value1' assert config.data['key2'] == 'value2' # replace config.data['key1'] = 'new value' config = client.replace(config) assert config.data['key1'] == 'new value' assert config.data['key2'] == 'value2' # patch with PatchType.STRATEGIC patch = {'metadata': {'labels': {'app': 'xyz'}}} config = client.patch(ConfigMap, name=obj_name, obj=patch) assert config.metadata.labels['app'] == 'xyz' # get config2 = client.get(ConfigMap, name=obj_name) assert config.metadata.creationTimestamp == config2.metadata.creationTimestamp # list configs = [config.metadata.name for config in client.list(ConfigMap)] assert obj_name in configs finally: client.delete(ConfigMap, name=obj_name)
def test_patching(obj_name): client = Client() service = Service( metadata=ObjectMeta(name=obj_name), spec=ServiceSpec( ports=[ServicePort(name='a', port=80, targetPort=8080)], selector={'app': 'not-existing'} ) ) # create client.create(service) try: # patch with PatchType.STRATEGIC patch = {'spec': {'ports': [{'name': 'b', 'port':81, 'targetPort': 8081}]}} service = client.patch(Service, name=obj_name, obj=patch) assert len(service.spec.ports) == 2 assert {port.name for port in service.spec.ports} == {'a', 'b'} # strategic - patch merge key: port # we also try to send a Resource type for patching patch = Service(spec=ServiceSpec(ports=[ServicePort(name='b', port=81, targetPort=8082)])) service = client.patch(Service, name=obj_name, obj=patch) assert len(service.spec.ports) == 2 for port in service.spec.ports: if port.port == 81: assert port.targetPort == 8082 # patch with PatchType.MERGE # merge will replace the full list patch = {'spec': {'ports': [{'name': 'b', 'port': 81, 'targetPort': 8081}]}} service = client.patch(Service, name=obj_name, obj=patch, patch_type=PatchType.MERGE) assert len(service.spec.ports) == 1 assert service.spec.ports[0].port == 81 # patch with PatchType.JSON patch = [ {'op': 'add', 'path': '/spec/ports/-', 'value': {'name': 'a', 'port': 80, 'targetPort': 8080}} ] service = client.patch(Service, name=obj_name, obj=patch, patch_type=PatchType.JSON) assert len(service.spec.ports) == 2 assert service.spec.ports[1].port == 80 finally: client.delete(Service, name=obj_name)
def test_create_namespaced(client: lightkube.Client): req = respx.post("https://localhost:9443/api/v1/namespaces/default/pods").respond(json={'metadata': {'name': 'xx'}}) pod = client.create(Pod(metadata=ObjectMeta(name="xx", labels={'l': 'ok'}))) assert req.calls[0][0].read() == b'{"metadata": {"labels": {"l": "ok"}, "name": "xx"}}' assert pod.metadata.name == 'xx' req2 = respx.post("https://localhost:9443/api/v1/namespaces/other/pods").respond(json={'metadata': {'name': 'yy'}}) pod = client.create(Pod(metadata=ObjectMeta(name="xx", labels={'l': 'ok'})), namespace='other') assert pod.metadata.name == 'yy' assert req2.calls[0][0].read() == b'{"metadata": {"labels": {"l": "ok"}, "name": "xx"}}' respx.post("https://localhost:9443/api/v1/namespaces/ns2/pods").respond( json={'metadata': {'name': 'yy'}}) pod = client.create(Pod(metadata=ObjectMeta(name="xx", labels={'l': 'ok'}, namespace='ns2'))) assert pod.metadata.name == 'yy' # namespace inside object definition need to match with provided namespace parameter. with pytest.raises(ValueError): client.create(Pod(metadata=ObjectMeta(name="xx", namespace='ns1')), namespace='ns2')
def test_deletecollection(obj_name): client = Client() config = ConfigMap( metadata=ObjectMeta(name=obj_name, namespace=obj_name), data={'key1': 'value1', 'key2': 'value2'} ) client.create(Namespace(metadata=ObjectMeta(name=obj_name))) try: # create client.create(config) config.metadata.name = f"{obj_name}-2" client.create(config) # k3s automatically create/recreate one extra configmap. maps = names(client.list(ConfigMap, namespace=obj_name)) assert obj_name in maps assert f"{obj_name}-2" in maps client.deletecollection(ConfigMap, namespace=obj_name) maps = names(client.list(ConfigMap, namespace=obj_name)) assert obj_name not in maps assert f"{obj_name}-2" not in maps finally: client.delete(Namespace, name=obj_name)
def test_wait_namespaced(resource, for_condition, spec): client = Client() requested = resource.from_dict( {"metadata": {"generateName": "e2e-test-"}, "spec": spec} ) created = client.create(requested) client.wait( resource, created.metadata.name, for_conditions=[for_condition], ) client.delete(resource, created.metadata.name)
def test_list_all_ns(obj_name): client = Client() ns1 = obj_name ns2 = f"{obj_name}-2" config = ConfigMap( metadata=ObjectMeta(name=obj_name), data={'key1': 'value1', 'key2': 'value2'} ) client.create(Namespace(metadata=ObjectMeta(name=ns1))) client.create(Namespace(metadata=ObjectMeta(name=ns2))) try: client.create(config, namespace=ns1) client.create(config, namespace=ns2) maps = [f"{cm.metadata.namespace}/{cm.metadata.name}" for cm in client.list(ConfigMap, namespace='*')] assert f"{ns1}/{obj_name}" in maps assert f"{ns2}/{obj_name}" in maps finally: client.delete(Namespace, name=ns1) client.delete(Namespace, name=ns2)
def test_create_global(client: lightkube.Client): req = respx.post("https://localhost:9443/api/v1/nodes").respond(json={'metadata': {'name': 'xx'}}) pod = client.create(Node(metadata=ObjectMeta(name="xx"))) assert req.calls[0][0].read() == b'{"metadata": {"name": "xx"}}' assert pod.metadata.name == 'xx'