Skip to content

[FEATURE] delete MPE on workspace when --force is set #73

Open

Description

Use Case / Problem

This was previously listed as a bug, however after feedback this instead should be a feature.

Currently when a workspace contains a Managed Private Endpoint (MPE) it will prevent the workspace from being deleted even when --force is set. This is inline with the current Fabric Portal:

Image

As the user is passing --force and thus wants to delete the workspace with all of its contents IMO it makes sense to delete the workspace regardless of MPEs being active on the workspace.

Proposed Solution

When --force is applied, first check whether there are any MPEs active. If yes, delete them and then proceed to delete the workspace. The output of the CLI would then give something like this:

$ fab rm ws1.Workspace -f
This will delete 0 underlying items
! Executing force delete
Deleting 'mpe1.ManagedPrivateEndpoint'...
* 'mpe1.ManagedPrivateEndpoint' deleted
! Executing force delete
Deleting 'ws1.Workspace'...
* 'ws1.Workspace' deleted

Alternatives Considered

Alternatives currently is to first list MPEs of a workspace, iteratively delete those and only then delete the workspace. This feels like a lot of extra steps.

Impact Assessment

  • This would help me personally
  • This would help my team/organization
  • This would help the broader fabric-cli community
  • This aligns with Microsoft Fabric roadmap items

Implementation Attestation

  • I understand this feature should maintain backward compatibility with existing commands
  • I confirm this feature request does not introduce performance regressions for existing workflows
  • I acknowledge that new features must follow fabric-cli's established patterns and conventions

Implementation Notes

Logic could be something like this, of course open for discussion :)

if force_delete:
    managed_private_endpoints = utils_mem_store.get_managed_private_endpoints_for_workspace(workspace)
    for managed_private_endpoint in managed_private_endpoints:
        args_ = deepcopy(args)
        args_.id = managed_private_endpoint.id
        args_.name = managed_private_endpoint.name
        if managedprivateendpoint_api.delete_managed_private_endpoint(args_, force_delete):
            utils_mem_store.delete_managed_identity_from_cache(managed_private_endpoint)

Activity

  1. aviatco commented on Nov 25, 2025

    @aviatco
    Collaborator

    Guust Franssens (@Guust-Franssens) Since currently removing a workspace that has an existing Managed Private Endpoint is not permitted, deleting the MPE on the user’s behalf requires explicit consent. I propose adding a confirmation prompt before deleting the MPE, giving the user the option to cancel the operation if they change their mind.

  2. Guust-Franssens commented on Nov 25, 2025

    @Guust-Franssens
    ContributorAuthor

    With confirmation the flow would look something like this:

    $ fab rm ws1.Workspace --force
    This will delete 0 underlying items
    ? This workspace contains 1 managed private endpoint(s), in order to delete the workspace these must be deleted first. Do you want to continue? No
    ! Deletion of workspace ws1.Workspace cancelled

    and

    $ fab rm ws1.Workspace --force
    This will delete 0 underlying items
    ? This workspace contains 1 managed private endpoint(s), in order to delete the workspace these must be deleted first. Do you want to continue? Yes
    Proceeding with deletion of managed private endpoints...
    ! Executing force delete
    Deleting 'mep1.ManagedPrivateEndpoint'...
    * 'mep1.ManagedPrivateEndpoint' deleted
    ! Executing force delete
    Deleting 'ws1.Workspace'...
    * 'ws1.Workspace' deleted

    aviatco How would a user overwrite the confirmation in a non-interactive CI/CD scenario? My understanding is that currently --force is being used throughout the CLI to bypass confirmation prompts.

    Is this feature open for contributions? If yes, could you label it with help wanted?

  3. aviatco commented on Nov 25, 2025

    @aviatco
    Collaborator

    Hasan Abo-Shally (@HasanAboShally) Alon Yeshurun (@ayeshurun) I will appreciate your input, particularly regarding how deletion should be handled in command-line and scripted execution scenarios. This includes ensuring proper user consent and maintaining consistency with interactive workflows.
    Maybe instead, we should use a new flag to approve the removal? something like --cascade_remove / --remove_dependencies
    or even more specific like: --remove_MPE

  4. HasanAboShally commented on Nov 27, 2025

    @HasanAboShally
    Collaborator

    /needinfo

    Thanks Guust Franssens (@Guust-Franssens) for the detailed feature request and the thoughtful discussion aviatco.

    Understanding Managed Private Endpoints (MPEs)

    Before diving into the solution, it's worth understanding why Fabric prevents workspace deletion when MPEs exist:

    MPEs are secure network connections that allow Fabric workloads (Spark notebooks, lakehouses, Eventstreams) to access data sources behind firewalls—like Azure Storage or Azure SQL Database—without exposing them to the public internet.

    The key reason Fabric blocks workspace deletion with active MPEs is likely to protect users from accidentally losing their private endpoint configurations. Unlike regular items, MPEs:

    • Often require external approval from the target resource owner (e.g., an Azure Storage admin must approve the connection request)
    • Can take significant time to set up and get re-approved
    • Represent a security-sensitive configuration that connects to protected resources

    That said, MPEs are entirely workspace-scoped—they serve only that specific workspace and don't affect or connect to other workspaces. Once the workspace is deleted, the MPE has no purpose anyway.

    The Current Challenge with --force

    The current --force flag in the CLI is a binary switch that, across different commands, generally means "skip confirmation prompts and proceed." However, when a user passes --force to delete a workspace, they're expressing clear intent to delete everything—yet the operation still fails if MPEs exist.

    This raises a broader design question: how should --force handle operations that require multiple distinct "forced" behaviors? Today it's MPEs, but tomorrow it could be other workspace-level dependencies.

    Proposed Solution: Value-based --force

    Rather than adding a new flag (like --cascade or --remove-mpe), I think we can extend --force to accept optional values that explicitly declare what should be forced:

    # Current behavior (unchanged) - skip confirmation prompts
    fab rm ws1.Workspace --force
    
    # New: explicitly force MPE deletion along with the workspace  
    fab rm ws1.Workspace --force=mpe
    
    # Future extensibility: combine multiple force behaviors
    fab rm ws1.Workspace --force=mpe,shortcuts

    Why this approach?

    1. Backward compatible — bare --force / -f keeps current behavior
    2. Explicit consent — users must explicitly opt-in to delete MPEs, addressing aviatco's concern about user consent
    3. Scriptable — works well in CI/CD pipelines without interactive prompts
    4. Extensible — easy to add new values in the future without flag proliferation
    5. Discoverable — --help can list all valid force values
    6. Familiar pattern — similar to kubectl delete --cascade=<value>

    Example UX:

    $ fab rm ws1.Workspace --force
    This will delete 0 underlying items
    x Cannot delete workspace: 1 managed private endpoint(s) exist.
      Use --force=mpe to also delete managed private endpoints.
    
    $ fab rm ws1.Workspace --force=mpe
    This will delete 0 underlying items
    Deleting 'mpe1.ManagedPrivateEndpoint'...
    ✓ 'mpe1.ManagedPrivateEndpoint' deleted
    Deleting 'ws1.Workspace'...
    ✓ 'ws1.Workspace' deleted

    This gives users a clear error message with actionable guidance, while ensuring they explicitly acknowledge the MPE deletion.


    What do you think about this direction? Happy to discuss further or explore alternative approaches.

  5. Guust-Franssens commented on Nov 27, 2025

    @Guust-Franssens
    ContributorAuthor

    Hi Hasan Abo-Shally (@HasanAboShally)
    Thanks for the detailed response. I am a big fan of your approach as it nicely strikes the balance between both mine and aviatco 's concerns. Especially since it would not add yet another argument that might lead us down a rabbit hole. A clean approach that didn't come to my mind 😄 !

    As you can probably tell, I have already been slightly tinkering with the code but haven't pushed the branch or made a PR. Is this something you as a team want to resolve or is it open for contribution?

  6. microsoft-github-policy-service commented on Nov 27, 2025

    @microsoft-github-policy-service

    Thank you for replying with additional information, Guust Franssens (@Guust-Franssens).
    A member of the Fabric CLI team will continue reviewing this issue.

  7. Guust-Franssens commented on Dec 3, 2025

    @Guust-Franssens
    ContributorAuthor
  8. HasanAboShally commented on Dec 8, 2025

    @HasanAboShally
    Collaborator

    Hey Guust Franssens (@Guust-Franssens) 👋 appologies for the delay.
    We're still discussing internally and I'll update soon.

    For this specific usecase, do you think checking the Managed Private Endpoints within the workspace prior to deleting could work? (e.g., fab ls ws1.Workspace/.managedprivateendpoints — more info here)

  9. Guust-Franssens commented on Dec 11, 2025

    @Guust-Franssens
    ContributorAuthor

    Yep that's the workaround I am currently using. Lmk once there is an update.

  10. HasanAboShally commented on Dec 16, 2025

    @HasanAboShally
    Collaborator

    Great! Sure, will update soon.
    Currently we're assessing the Value-based --force which I mentioned above and whether we want to change that now, vs adding a dedicated flag such as --cascade or --remove-mpe.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions