def test_patch_namespaced(client: lightkube.Client): # Default PatchType.STRATEGIC req = respx.patch("https://localhost:9443/api/v1/namespaces/default/pods/xx").respond(json={'metadata': {'name': 'xx'}}) pod = client.patch(Pod, "xx", Pod(metadata=ObjectMeta(labels={'l': 'ok'}))) assert pod.metadata.name == 'xx' assert req.calls[0][0].headers['Content-Type'] == "application/strategic-merge-patch+json" # PatchType.MERGE req = respx.patch("https://localhost:9443/api/v1/namespaces/other/pods/xx").respond(json={'metadata': {'name': 'xx'}}) pod = client.patch(Pod, "xx", Pod(metadata=ObjectMeta(labels={'l': 'ok'})), namespace='other', patch_type=types.PatchType.MERGE, force=True) assert pod.metadata.name == 'xx' assert req.calls[0][0].headers['Content-Type'] == "application/merge-patch+json" assert 'force' not in str(req.calls[0][0].url) # force is ignored for non APPLY patch types # PatchType.APPLY req = respx.patch("https://localhost:9443/api/v1/namespaces/other/pods/xy?fieldManager=test").respond( json={'metadata': {'name': 'xy'}}) pod = client.patch(Pod, "xy", Pod(metadata=ObjectMeta(labels={'l': 'ok'})), namespace='other', patch_type=types.PatchType.APPLY, field_manager='test') assert pod.metadata.name == 'xy' assert req.calls[0][0].headers['Content-Type'] == "application/apply-patch+yaml" # PatchType.APPLY + force req = respx.patch("https://localhost:9443/api/v1/namespaces/other/pods/xz?fieldManager=test&force=true").respond( json={'metadata': {'name': 'xz'}}) pod = client.patch(Pod, "xz", Pod(metadata=ObjectMeta(labels={'l': 'ok'})), namespace='other', patch_type=types.PatchType.APPLY, field_manager='test', force=True) assert pod.metadata.name == 'xz' assert req.calls[0][0].headers['Content-Type'] == "application/apply-patch+yaml" # PatchType.APPLY without field_manager with pytest.raises(ValueError, match="field_manager"): client.patch(Pod, "xz", Pod(metadata=ObjectMeta(labels={'l': 'ok'})), namespace='other', patch_type=types.PatchType.APPLY)
def test_replace_namespaced(client: lightkube.Client): req = respx.put("https://localhost:9443/api/v1/namespaces/default/pods/xy").respond(json={'metadata': {'name': 'xy'}}) pod = client.replace(Pod(metadata=ObjectMeta(name="xy"))) assert req.calls[0][0].read() == b'{"metadata": {"name": "xy"}}' assert pod.metadata.name == 'xy' respx.put("https://localhost:9443/api/v1/namespaces/other/pods/xz").respond(json={'metadata': {'name': 'xz'}}) pod = client.replace(Pod(metadata=ObjectMeta(name="xz")), namespace='other') assert pod.metadata.name == 'xz' # namespace inside object definition need to match with provided namespace parameter. with pytest.raises(ValueError): client.replace(Pod(metadata=ObjectMeta(name="xx", namespace='ns1')), namespace='ns2')
def generate_pod_resource_list(pod_names): resources = [ Pod(kind="Pod", metadata=ObjectMeta(name=str(name))) for name in pod_names ] return resources
async def test_patch_global(client: lightkube.AsyncClient): req = respx.patch("https://localhost:9443/api/v1/nodes/xx").respond( json={'metadata': { 'name': 'xx' }}) pod = await client.patch(Node, "xx", [{ "op": "add", "path": "/metadata/labels/x", "value": "y" }], patch_type=types.PatchType.JSON) assert pod.metadata.name == 'xx' assert req.calls[0][0].headers[ 'Content-Type'] == "application/json-patch+json" # PatchType.APPLY + force req = respx.patch( "https://localhost:9443/api/v1/nodes/xy?fieldManager=test&force=true" ).respond(json={'metadata': { 'name': 'xy' }}) node = await client.patch(Node, "xy", Pod(metadata=ObjectMeta(labels={'l': 'ok'})), patch_type=types.PatchType.APPLY, field_manager='test', force=True) assert node.metadata.name == 'xy' assert req.calls[0][0].headers[ 'Content-Type'] == "application/apply-patch+yaml" await client.close()
def test_field_manager(kubeconfig): config = KubeConfig.from_file(str(kubeconfig)) client = lightkube.Client(config=config, field_manager='lightkube') respx.patch("https://localhost:9443/api/v1/nodes/xx?fieldManager=lightkube").respond(json={'metadata': {'name': 'xx'}}) client.patch(Node, "xx", [{"op": "add", "path": "/metadata/labels/x", "value": "y"}], patch_type=types.PatchType.JSON) respx.post("https://localhost:9443/api/v1/namespaces/default/pods?fieldManager=lightkube").respond(json={'metadata': {'name': 'xx'}}) client.create(Pod(metadata=ObjectMeta(name="xx", labels={'l': 'ok'}))) respx.put("https://localhost:9443/api/v1/namespaces/default/pods/xy?fieldManager=lightkube").respond( json={'metadata': {'name': 'xy'}}) client.replace(Pod(metadata=ObjectMeta(name="xy"))) respx.put("https://localhost:9443/api/v1/namespaces/default/pods/xy?fieldManager=override").respond( json={'metadata': {'name': 'xy'}}) client.replace(Pod(metadata=ObjectMeta(name="xy")), field_manager='override')
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_apply_namespaced(client: lightkube.Client): req = respx.patch("https://localhost:9443/api/v1/namespaces/default/pods/xy?fieldManager=test").respond( json={'metadata': {'name': 'xy'}}) pod = client.apply(Pod(metadata=ObjectMeta(name='xy')), field_manager='test') assert pod.metadata.name == 'xy' assert req.calls[0][0].headers['Content-Type'] == "application/apply-patch+yaml" # custom namespace, force req = respx.patch("https://localhost:9443/api/v1/namespaces/other/pods/xz?fieldManager=a&force=true").respond( json={'metadata': {'name': 'xz'}}) pod = client.apply(Pod(metadata=ObjectMeta(name='xz', namespace='other')), field_manager='a', force=True) assert pod.metadata.name == 'xz' assert req.calls[0][0].headers['Content-Type'] == "application/apply-patch+yaml" # sub-resource req = respx.patch("https://localhost:9443/api/v1/namespaces/default/pods/xx/status?fieldManager=a").respond( json={'metadata': {'name': 'xx'}}) pod = client.apply(Pod.Status(), name='xx', field_manager='a') assert pod.metadata.name == 'xx' assert req.calls[0][0].headers['Content-Type'] == "application/apply-patch+yaml"
def create_pod(name, command) -> Pod: return Pod( metadata=ObjectMeta(name=name, labels={'app-name': name}), spec=PodSpec(containers=[Container( name='main', image='busybox', args=[ "/bin/sh", "-c", command ], )], terminationGracePeriodSeconds=1) )
delete_calls = tuple() names_deleted = tuple(c.args[0].metadata.name for c in delete_calls) assert sorted(names_deleted) == sorted(expected_resources_deleted_names) # Assert apply called if it should have been called assert rh.apply_manifest.call_count == 1 resources_applied = mocked_load_all_yaml.return_value if resources_applied is None: resources_applied = tuple() names_applied = tuple(r.metadata.name for r in resources_applied) assert sorted(names_applied) == sorted(desired_resource_names) # Resources for below tests POD_LIST_1 = [ Pod(kind="Pod", metadata=ObjectMeta(name=f"pod-{n}", namespace="some-namespace")) for n in range(5) ] POD_TUPLES_1 = [("Pod", f"pod-{n}") for n in range(0, 5)] POD_LIST_2 = [ Pod(kind="Pod", metadata=ObjectMeta(name=f"pod-{n}", namespace="some-namespace")) for n in range(3, 7) ] POD_TUPLES_IN_1_NOT_2 = [("Pod", f"pod-{n}") for n in range(0, 3)] @pytest.mark.parametrize( "left,right,expected_result", [ (POD_LIST_1, POD_LIST_1, []),