Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check volume sources and attachment #1186

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 70 additions & 35 deletions harvester_e2e_tests/integrations/test_1_volumes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

pytest_plugins = [
'harvester_e2e_tests.fixtures.api_client',
"harvester_e2e_tests.fixtures.images"
]


@pytest.fixture(scope="module")
def focal_image(api_client, unique_name, image_ubuntu, polling_for):
image_name = f"img-focal-{unique_name}"
def ubuntu_image(api_client, unique_name, image_ubuntu, polling_for):
image_name = f"img-{unique_name}"

code, data = api_client.images.create_by_url(image_name, image_ubuntu.url)
assert 201 == code, f"Fail to create image\n{code}, {data}"
Expand All @@ -30,11 +31,11 @@ def focal_image(api_client, unique_name, image_ubuntu, polling_for):


@pytest.fixture(scope="class")
def focal_vm(api_client, unique_name, focal_image, polling_for):
vm_name = f"vm-focal-{unique_name}"
def ubuntu_vm(api_client, unique_name, ubuntu_image, polling_for):
vm_name = f"vm-{unique_name}"

vm_spec = api_client.vms.Spec(1, 2)
vm_spec.add_image(vm_name, focal_image["id"])
vm_spec.add_image(vm_name, ubuntu_image["id"])
code, data = api_client.vms.create(vm_name, vm_spec)
assert 201 == code, f"Fail to create VM\n{code}, {data}"
code, data = polling_for(
Expand Down Expand Up @@ -69,17 +70,13 @@ def focal_vm(api_client, unique_name, focal_image, polling_for):
@pytest.mark.p0
@pytest.mark.volumes
@pytest.mark.parametrize("create_as", ["json", "yaml"])
def test_create_volume_backing_image(api_client, unique_name, polling_for, focal_image, create_as):
"""
1. Create a new image from URL
2. Check that it is created succesffully.
3. Create a new volume with the image_id of the previous image
4. Check that the new image is created
5. Delete image and volume
"""
image_id, display_name = focal_image['id'], focal_image['display_name']

spec = api_client.volumes.Spec("10Gi", f"longhorn-{display_name}")
@pytest.mark.parametrize("source_type", ["New", "VM Image"])
def test_create_volume(api_client, unique_name, ubuntu_image, create_as, source_type, polling_for):
image_id, storage_cls = None, None
if source_type == "VM Image":
image_id, storage_cls = ubuntu_image['id'], f"longhorn-{ubuntu_image['display_name']}"

spec = api_client.volumes.Spec("10Gi", storage_cls)
if create_as == 'yaml':
kws = dict(headers={'Content-Type': 'application/yaml'}, json=None,
data=yaml.dump(spec.to_dict(unique_name, 'default', image_id=image_id)))
Expand All @@ -88,15 +85,25 @@ def test_create_volume_backing_image(api_client, unique_name, polling_for, focal
code, data = api_client.volumes.create(unique_name, spec, image_id=image_id, **kws)
assert 201 == code, (code, unique_name, data, image_id)

# Verify: volume created & bounded & based on image & name is correct
polling_for("volume do created",
lambda code, data: 200 == code and data['status']['phase'] == "Bound",
api_client.volumes.get, unique_name)

code, data = api_client.volumes.get(unique_name)
mdata, annotations = data['metadata'], data['metadata']['annotations']
assert 200 == code, (code, data)
assert data['status']['phase'] == "Bound", (data)
assert image_id == data['metadata']['annotations']['harvesterhci.io/imageId']
assert unique_name == data['metadata']['name'], (code, data)
assert unique_name == mdata['name'], (code, data)
# status
assert not mdata['state']['error'], (code, data)
assert not mdata['state']['transitioning'], (code, data)
assert data['status']['phase'] == "Bound", (code, data)
# source
if source_type == "VM Image":
assert image_id == annotations['harvesterhci.io/imageId'], (code, data)
else:
assert not annotations.get('harvesterhci.io/imageId'), (code, data)
# attachment
assert not annotations.get("harvesterhci.io/owned-by"), (code, data)

# teardown
polling_for("volume do deleted", lambda code, _: 404 == code,
Expand All @@ -106,31 +113,31 @@ def test_create_volume_backing_image(api_client, unique_name, polling_for, focal
@pytest.mark.p0
@pytest.mark.volumes
class TestVolumeWithVM:
def pause_vm(self, api_client, focal_vm, polling_for):
vm_name = focal_vm['metadata']['name']
def pause_vm(self, api_client, ubuntu_vm, polling_for):
vm_name = ubuntu_vm['metadata']['name']
code, data = api_client.vms.pause(vm_name)
assert 204 == code, f"Fail to pause VM\n{code}, {data}"
polling_for("VM do paused",
lambda c, d: d.get('status', {}).get('printableStatus') == "Paused",
api_client.vms.get, vm_name)

def stop_vm(self, api_client, focal_vm, polling_for):
vm_name = focal_vm['metadata']['name']
def stop_vm(self, api_client, ubuntu_vm, polling_for):
vm_name = ubuntu_vm['metadata']['name']
code, data = api_client.vms.stop(vm_name)
assert 204 == code, f"Fail to stop VM\n{code}, {data}"
polling_for("VM do stopped",
lambda c, d: 404 == c,
api_client.vms.get_status, vm_name)

def delete_vm(self, api_client, focal_vm, polling_for):
vm_name = focal_vm['metadata']['name']
def delete_vm(self, api_client, ubuntu_vm, polling_for):
vm_name = ubuntu_vm['metadata']['name']
code, data = api_client.vms.delete(vm_name)
assert 200 == code, f"Fail to delete VM\n{code}, {data}"
polling_for("VM do deleted",
lambda c, d: 404 == c,
api_client.vms.get, vm_name)

def test_delete_volume_bounded_on_existing_vm(self, api_client, focal_vm, polling_for):
def test_delete_volume_on_existing_vm(self, api_client, ubuntu_image, ubuntu_vm, polling_for):
"""
1. Create a VM with volume
2. Delete volume should reply 422
Expand All @@ -140,35 +147,63 @@ def test_delete_volume_bounded_on_existing_vm(self, api_client, focal_vm, pollin
6. Delete volume should reply 422 too
Ref. https://github.com/harvester/tests/issues/905
"""
vol_name = (focal_vm["spec"]["template"]["spec"]["volumes"][0]
['persistentVolumeClaim']['claimName'])
vol_name = (ubuntu_vm["spec"]["template"]["spec"]["volumes"][0]
['persistentVolumeClaim']['claimName'])

code, data = api_client.volumes.delete(vol_name)
assert 422 == code, f"Should fail to delete volume\n{code}, {data}"

self.pause_vm(api_client, focal_vm, polling_for)
self.pause_vm(api_client, ubuntu_vm, polling_for)
code, data = api_client.volumes.delete(vol_name)
assert 422 == code, f"Should fail to delete volume\n{code}, {data}"

self.stop_vm(api_client, focal_vm, polling_for)
self.stop_vm(api_client, ubuntu_vm, polling_for)
code, data = api_client.volumes.delete(vol_name)
assert 422 == code, f"Should fail to delete volume\n{code}, {data}"

def test_delete_volume_bounded_on_deleted_vm(self, api_client, focal_vm, polling_for):
# Check Volume
code, data = api_client.volumes.get(vol_name)
mdata, annotations = data['metadata'], data['metadata']['annotations']
assert 200 == code, (code, data)
assert mdata['name'] == vol_name, (code, data)
# status
assert not mdata['state']['error'], (code, data)
assert not mdata['state']['transitioning'], (code, data)
assert data['status']['phase'] == "Bound", (code, data)
# source
assert ubuntu_image["id"] == annotations['harvesterhci.io/imageId'], (code, data)
# attachment
assert ubuntu_vm['id'] in annotations.get("harvesterhci.io/owned-by"), data

def test_delete_volume_on_deleted_vm(self, api_client, ubuntu_image, ubuntu_vm, polling_for):
"""
1. Create a VM with volume
2. Delete volume should reply 422
3. Delete VM but not volume
4. Delete volume should reply 200
Ref. https://github.com/harvester/tests/issues/652
"""
vol_name = (focal_vm["spec"]["template"]["spec"]["volumes"][0]
['persistentVolumeClaim']['claimName'])
vol_name = (ubuntu_vm["spec"]["template"]["spec"]["volumes"][0]
['persistentVolumeClaim']['claimName'])

code, data = api_client.volumes.delete(vol_name)
assert 422 == code, f"Should fail to delete volume\n{code}, {data}"

self.delete_vm(api_client, focal_vm, polling_for)
self.delete_vm(api_client, ubuntu_vm, polling_for)

code, data = api_client.volumes.delete(vol_name)
assert 200 == code, f"Fail to delete volume\n{code}, {data}"

# Check Volume
code, data = api_client.volumes.get(vol_name)
mdata, annotations = data['metadata'], data['metadata']['annotations']
assert 200 == code, (code, data)
assert mdata['name'] == vol_name, (code, data)
# status
assert not mdata['state']['error'], (code, data)
assert not mdata['state']['transitioning'], (code, data)
assert data['status']['phase'] == "Bound", (code, data)
# source
assert ubuntu_image["id"] == annotations['harvesterhci.io/imageId'], (code, data)
# attachment
assert not annotations.get("harvesterhci.io/owned-by"), (code, data)