Skip to content

setup IOPS using annotations#717

Open
boddumanohar wants to merge 4 commits intodevfrom
set-iops-using-annotations
Open

setup IOPS using annotations#717
boddumanohar wants to merge 4 commits intodevfrom
set-iops-using-annotations

Conversation

@boddumanohar
Copy link
Copy Markdown
Member

@boddumanohar boddumanohar commented Apr 2, 2026

fixes: simplyblock/vela#310

PR simplyblock/simplyblock-csi#294 introduces setting IOPS values using annotations.

example: simplybk/qos-rw-iops: "1000"

This will essentially remove the need for having to create a storage class.

At the moment, for every branch we create a storage class. This to override the IOPS setting. Now that we can set the IOPS using annotation, there is no need to create a storage class.

But with this approach when a branch is cloned/restored it will use the SIMPLYBLOCK_CSI_STORAGE_CLASS storage class which doesn't have IOPS QOS set. So we explicitly call update_branch_volume_iops

Test cases:

  • create a new branch should have IOPS set correctly
  • Resize IOPS should should work correctly
  • Branch clone with the default values inherits the IOPS from the parent branch
  • Branch clone with override parameters inherits the IOPS from the parent branch
  • Branch restore with default parameters inherits IOPS from the parent branch

Copy link
Copy Markdown
Collaborator

@mxsrc mxsrc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing the constant into the storage-class parameters, we should remove those parameters altogether, there's no need for them anymore.

Copy link
Copy Markdown
Collaborator

@mxsrc mxsrc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better! There are a few open quesitions I added as comments. Additionally, there are unused functions now, in particular I spotted simplyblock.vela.deployment.kubernetes.{get,delete}_storage_class. There might be others, imho they can be removed, if we need this functionality in the future we can re-introduce it.

Comment on lines +312 to +341
_, autoscaler_vm_name = get_autoscaler_vm_identity(branch_id)
pvc_names = (
f"{autoscaler_vm_name}{AUTOSCALER_PVC_SUFFIX}",
f"{autoscaler_vm_name}{AUTOSCALER_WAL_PVC_SUFFIX}",
f"{autoscaler_vm_name}{STORAGE_PVC_SUFFIX}",
)

async def _resolve_existing_volume(pvc_name: str) -> UUID | None:
try:
volume, _ = await _resolve_volume_identifiers(namespace, pvc_name)
except (VelaDeploymentError, VelaKubernetesError) as exc:
if "not found" in str(exc).lower():
return None
raise
return volume

resolved_volumes = await asyncio.gather(*(_resolve_existing_volume(pvc_name) for pvc_name in pvc_names))
volumes = tuple(dict.fromkeys(volume for volume in resolved_volumes if volume is not None))
if not volumes:
raise VelaDeploymentError(f"Failed to resolve any Simplyblock volumes for branch {branch_id}")

volume, _ = await resolve_autoscaler_volume_identifiers(namespace)
try:
async with create_simplyblock_api() as sb_api:
await sb_api.update_volume(volume=volume, payload={"max_rw_iops": iops})
await asyncio.gather(
*(sb_api.update_volume(volume=volume, payload={"max_rw_iops": iops}) for volume in volumes)
)
except VelaSimplyblockAPIError as exc:
raise VelaDeploymentError("Failed to update volume") from exc

logger.info("Updated Simplyblock volume %s IOPS to %s", volume, iops)


async def ensure_branch_storage_class(branch_id: Identifier, *, iops: int) -> str:
storage_class_name = branch_storage_class_name(branch_id)
try:
await kube_service.get_storage_class(storage_class_name)
logger.info("StorageClass %s already exists; reusing", storage_class_name)
return storage_class_name
except VelaKubernetesError:
pass

base_storage_class = await kube_service.get_storage_class(SIMPLYBLOCK_CSI_STORAGE_CLASS)
storage_class_manifest = _build_storage_class_manifest(
storage_class_name=storage_class_name,
iops=iops,
base_storage_class=base_storage_class,
)
await kube_service.apply_storage_class(storage_class_manifest)
return storage_class_name
logger.info("Updated Simplyblock volumes %s IOPS to %s", list(volumes), iops)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions:

  • Why are we going through the simplyblock API here? In other places annotations to the PVC are sufficient.
  • If we do in fact have to go through the API, a helper to set the IOPS of a PVC would make this more readable.

new_manifest.spec.storage_class_name = SIMPLYBLOCK_CSI_STORAGE_CLASS
if hasattr(new_manifest.spec, "storageClassName"):
new_manifest.spec.storageClassName = self.storage_class_name
new_manifest.spec.storageClassName = SIMPLYBLOCK_CSI_STORAGE_CLASS
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, why do we have to handle the different cases?

@@ -101,7 +99,7 @@ def build_pvc_manifest_from_existing(
access_modes = list(getattr(spec, "access_modes", None) or [])
storage_class_name = getattr(spec, "storage_class_name", None) or getattr(spec, "storageClassName", None)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we checking snake case here? According to the docs only camel case is expected. These lines could be

storage_class_name = getattr(spec, "storageClassName", SIMPLYBLOCK_CSI_STORAGE_CLASS)

or just using the constant in all cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants