From dd3bc022b7803f452f604ebaa7054c229314ae2c Mon Sep 17 00:00:00 2001 From: "QUALISYSTEMS\\nahum-t" Date: Mon, 27 Jul 2026 11:17:46 +0300 Subject: [PATCH 1/2] Track 3 Tier 1: API how-tos + abstract-resolution diagnostics Adds usage guides for three previously-undocumented CloudShell Automation API methods (GetResourceReservations, UndeployApps, RemoveEntitiesFromTopology) and a troubleshooting section on reading the resolution-failure 'View Details' diagnostic. Grounded in the server code and integration test scenarios. Co-Authored-By: Claude Opus 4.8 (1M context) --- .wordlist.txt | 5 + .../get-resource-reservations.md | 93 +++++++++++++++++++ .../remove-entities-from-topology.md | 52 +++++++++++ .../undeploy-apps-in-sandbox.md | 67 +++++++++++++ ...fails-on-nonexistent-resource-conflicts.md | 31 +++++++ 5 files changed, 248 insertions(+) create mode 100644 docs/devguide/available-cs-api/useful-cs-api-examples/get-resource-reservations.md create mode 100644 docs/devguide/available-cs-api/useful-cs-api-examples/remove-entities-from-topology.md create mode 100644 docs/devguide/available-cs-api/useful-cs-api-examples/undeploy-apps-in-sandbox.md diff --git a/.wordlist.txt b/.wordlist.txt index 0fe908e704..cea031af14 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1642,3 +1642,8 @@ copiable dialogs unresolvable revalidation +Undeploying +undeploy +undeploys +paginated +pagination diff --git a/docs/devguide/available-cs-api/useful-cs-api-examples/get-resource-reservations.md b/docs/devguide/available-cs-api/useful-cs-api-examples/get-resource-reservations.md new file mode 100644 index 0000000000..6eea8b6ed1 --- /dev/null +++ b/docs/devguide/available-cs-api/useful-cs-api-examples/get-resource-reservations.md @@ -0,0 +1,93 @@ +--- +sidebar_position: 6 +--- + +# Getting a Resource's Reservations + +The `GetResourceReservations` API returns the reservations (sandboxes) associated with a specific resource. This is useful for admin and reporting automation - for example, to check whether a resource is currently in use before taking it offline, to audit which users have reserved a resource, or to list its upcoming (scheduled) reservations. + +The API returns three kinds of reservations for the resource: + +- **Active** - a reservation that is currently running. +- **Pending** - a future (scheduled) reservation that has not started yet. +- **Completed** - a historical reservation that has already ended. + +Results are paginated, so you can cap how many entries are returned while still learning the total number of matching reservations. + +## How it works + +`GetResourceReservations` accepts three parameters: + +| Parameter | Type | Description | +| --- | --- | --- | +| `resourceFullPath` | string | The full path/name of the resource whose reservations you want to retrieve. This is required. | +| `includeHistorical` | bool | When `true`, completed (ended) reservations are included in the results. When `false`, only active and pending (future) reservations are returned. Defaults to `true`. | +| `maxResults` | int | The maximum number of reservation entries to return. Defaults to `50`. Values of `0` or less fall back to `50`, and the server caps this at `200`. | + +:::note +Setting `includeHistorical` to `false` filters out completed reservations only. Pending (future) reservations always appear in the results regardless of the `includeHistorical` value, since a future reservation is not historical. +::: + +The call returns a response object with the following fields: + +- `ResourceName` - the resource full path that was queried. +- `TotalCount` - the total number of reservations that match the query. This reflects **all** matching reservations, even when `maxResults` caps the number of entries actually returned - so you can detect when there are more reservations than the page you requested. +- `Reservations` - the list of reservation entries. Each entry has: + - `ReservationId` - the reservation's id. + - `ReservationName` - the reservation's name. + - `Status` - `Active`, `Pending`, or `Completed`. + - `OwnerName` - the username of the reservation's owner. + - `StartTime` - the reservation's start time. + - `EndTime` - the reservation's end time. + +## Python example + +This script starts an API session and prints the reservations for a target resource. Replace `resource name` with your resource's full path and set your CloudShell connection details. As this uses the CloudShell Automation API package, make sure to first install it by running `pip install cloudshell-automation-api` from command-line. + +```python +from cloudshell.api.cloudshell_api import CloudShellAPISession + +# specify target resource full path +TARGET_RESOURCE = "resource name" + +# api session details +user = "admin" +password = "admin" +server = "localhost" +domain = "Global" + +# start session +api = CloudShellAPISession(host=server, username=user, password=password, domain=domain) + +# retrieve the resource's reservations (active, pending and completed), up to 50 entries +response = api.GetResourceReservations(resourceFullPath=TARGET_RESOURCE, + includeHistorical=True, + maxResults=50) + +print("Resource '{}' has {} reservation(s):".format(response.ResourceName, response.TotalCount)) + +for reservation in response.Reservations: + print(" [{status}] {name} (id: {id}) - owner: {owner}, {start} to {end}".format( + status=reservation.Status, + name=reservation.ReservationName, + id=reservation.ReservationId, + owner=reservation.OwnerName, + start=reservation.StartTime, + end=reservation.EndTime)) + +# example: warn if the resource is currently in use +active = [r for r in response.Reservations if r.Status == "Active"] +if active: + print("\nResource is currently active in {} reservation(s).".format(len(active))) +``` + +To retrieve only the resource's current and upcoming reservations (excluding completed ones), call the API with `includeHistorical=False`: + +```python +# only active and pending (future) reservations +response = api.GetResourceReservations(resourceFullPath=TARGET_RESOURCE, + includeHistorical=False, + maxResults=50) +``` + +Because `TotalCount` reflects all matching reservations - not just the returned page - you can compare it against the number of returned entries to know when a resource has more reservations than the page you requested, and raise `maxResults` (up to `200`) accordingly. diff --git a/docs/devguide/available-cs-api/useful-cs-api-examples/remove-entities-from-topology.md b/docs/devguide/available-cs-api/useful-cs-api-examples/remove-entities-from-topology.md new file mode 100644 index 0000000000..f1b5f26df7 --- /dev/null +++ b/docs/devguide/available-cs-api/useful-cs-api-examples/remove-entities-from-topology.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 8 +--- + +# Removing Entities from a Topology + +The `RemoveEntitiesFromTopology` API enables you to programmatically remove elements from a topology (blueprint), including services and abstract resources. This is useful when you want to automate cleanup or restructuring of a blueprint's contents from outside CloudShell, for example as part of a maintenance script that trims obsolete services or abstract resources from a set of blueprints. + +:::note Notes for RemoveEntitiesFromTopology: +- The topology is identified by its **name**, and the entities to remove are identified by their **ids**. +- Removing an entity also removes anything associated with it in the blueprint diagram, such as the routes and connectors attached to it. +- When you remove a root abstract resource, its child abstract resources are removed along with it. +::: + +## How it works + +`RemoveEntitiesFromTopology` accepts two parameters: + +- `topologyName` (string) - the name of the topology (blueprint) to remove entities from. +- `entityIds` (list of strings) - the ids of the entities to remove. Each id is the entity's unique identifier within the topology. + +You can mix entity types in a single call - for example, remove one or more services together with one or more abstract resources in the same request. + +To build the `entityIds` list, you first need to obtain the ids of the entities you want to remove. You can get these from the blueprint's details when you query it through the API. + +## Python example + +The following script starts an API session, finds the ids of the entities to remove from a blueprint, and calls `RemoveEntitiesFromTopology`. + +```python +from cloudshell.api.cloudshell_api import CloudShellAPISession + +# add credentials +user = "admin" +password = "admin" +server = "localhost" +domain = "Global" + +# start session +api = CloudShellAPISession(host=server, username=user, password=password, domain=domain) + +topology_name = "MyTopology" + +# the ids of the service and abstract resource entities to remove from the blueprint +entity_ids = [ + "3f2504e0-4f89-41d3-9a0c-0305e82c3301", + "9a0c0305-e82c-4f89-41d3-3f2504e04f89", +] + +# remove the entities from the topology +api.RemoveEntitiesFromTopology(topologyName=topology_name, entityIds=entity_ids) +``` diff --git a/docs/devguide/available-cs-api/useful-cs-api-examples/undeploy-apps-in-sandbox.md b/docs/devguide/available-cs-api/useful-cs-api-examples/undeploy-apps-in-sandbox.md new file mode 100644 index 0000000000..833c62ace4 --- /dev/null +++ b/docs/devguide/available-cs-api/useful-cs-api-examples/undeploy-apps-in-sandbox.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 7 +--- + +# Undeploying Apps While Keeping the Resource + +The `UndeployApps` API removes a deployed App from the cloud provider (it destroys the virtual machine) while **keeping the App's CloudShell resource** in place. This is different from deleting an App, which both destroys the VM on the cloud provider *and* removes the resource from CloudShell. + +The main use case is **bulk teardown**. When you need to clean up many deployed Apps, you can call `UndeployApps` first to destroy all the cloud-provider VMs in one request, and only then remove the CloudShell resources. Batching the cloud-provider deletes up front means the subsequent resource delete has much less work to do per resource, so it runs faster and more reliably. + +:::note Notes for UndeployApps: +- Applies to deployed Apps. Only deployed App resources (Apps that have a VM on the cloud provider) are acted on; other resources passed in are ignored. +- The App's CloudShell resource is **not** removed. Only the cloud-provider VM is destroyed and its VM reference cleared. +- Supported in CloudShell Automation API and TestShell API. +- This is a potentially long-running call. The API client sets a two-hour operation timeout for it, so it is safe to pass many Apps in a single request. +::: + +## How it works + +`UndeployApps` accepts a single parameter: + +- **resourcesFullPath** (`string[]`, mandatory) - a list of resource names. You can also include the full path from the root to the resource before the resource name, separated by slashes, for example `FolderName/ResourceName`. + +There is no reservation id parameter - the resources are identified by name or full path. + +For each resource in the list that is a deployed App, CloudShell runs the App's **Destroy** operation on the cloud provider and then clears the VM reference from the resource. The CloudShell resource itself remains, so anything that references it (routes, connectors, attributes) stays intact. + +If one or more Apps fail to be destroyed on the cloud provider, the call fails and reports the names of the Apps that could not be removed. + +### Contrast with deleting Apps + +- `UndeployApps` - destroys the cloud-provider VM and clears its VM reference. **The resource is kept.** +- Deleting an App (for example, via the delete flow that removes the resource from the inventory) - destroys the cloud-provider VM **and** removes the resource from CloudShell. + +Use `UndeployApps` when you want to release cloud infrastructure but keep the CloudShell resource, or as the fast first pass in a bulk teardown before you delete the resources themselves. + +## Python CloudShell Automation API example + +The following example starts an API session, finds the deployed Apps you want to tear down, and undeploys them in a single bulk call. Because `UndeployApps` only clears the cloud-provider VMs, a real teardown flow would follow it with `DeleteResources` to remove the CloudShell resources. + +```python +from cloudshell.api.cloudshell_api import CloudShellAPISession + +# start session +user = "admin" +password = "admin" +server = "localhost" +domain = "Global" +api = CloudShellAPISession(host=server, username=user, password=password, domain=domain) + +# the deployed Apps you want to remove from the cloud provider. +# each item is a resource name, optionally prefixed with its folder path. +apps_to_undeploy = [ + "Web Server 1", + "Web Server 2", + "MyFolder/DB Server 1", +] + +# bulk pass 1: destroy all the cloud-provider VMs, keep the CloudShell resources +api.UndeployApps(resourcesFullPath=apps_to_undeploy) + +# bulk pass 2 (optional): now delete the (already-undeployed) resources from CloudShell. +# because the VMs are already gone, this pass is faster and more reliable. +api.DeleteResources(resourcesFullPath=apps_to_undeploy) +``` + +If you only want to release the cloud infrastructure and keep the resources in CloudShell, omit the second `DeleteResources` call. diff --git a/docs/troubleshooting/cloudshell-portal/reserving-blueprints-fails-on-nonexistent-resource-conflicts.md b/docs/troubleshooting/cloudshell-portal/reserving-blueprints-fails-on-nonexistent-resource-conflicts.md index d0c099fd9c..b6a67b94e0 100644 --- a/docs/troubleshooting/cloudshell-portal/reserving-blueprints-fails-on-nonexistent-resource-conflicts.md +++ b/docs/troubleshooting/cloudshell-portal/reserving-blueprints-fails-on-nonexistent-resource-conflicts.md @@ -16,3 +16,34 @@ Reserving a blueprint that has resources displays errors relating to resource co ## Solutions See [Unable to Locate a Resource](./unable-to-locate-a-resource.md). + +## Reading the resolution diagnostics + +When a blueprint reservation fails, CloudShell tries to match each of the blueprint's abstract requirements to a real resource in your domain (and to find valid routes between them). Depending on *why* the match failed, the failure notification gives you one of two different tools for understanding what went wrong. + +### When abstract requirements cannot be resolved at all + +If the reservation fails because one or more abstract requirements have **no matching resource in the domain** — that is, nothing exists that meets the requirement's family, model, or attribute restrictions — the failure notification includes a **View Details** link with a detailed resolution diagnostic. + +Click **View Details** to see a breakdown of the reservation attempt, organized into the following categories: + +- **Unresolvable** – the abstract requirements that could not be matched to any resource, so no candidate exists to reserve. +- **Conflict-blocked** – requirements that *did* match one or more resources, but every matching resource is currently reserved by another sandbox. +- **Resolved** – the requirements that were successfully matched, shown together with the resource each was bound to. +- **Routes** – any route or L1 connectivity requirements that could not be satisfied, such as when two resolved endpoints have no valid path between them. + +Use this breakdown to remediate the specific cause. For example, an **Unresolvable** entry usually means the required resource type, model, or attribute value does not exist in your domain, is excluded, is not searchable, or is not associated with your domain — see [Unable to Locate a Resource](./unable-to-locate-a-resource.md). A **Routes** entry points to missing network connectivity rather than to a missing endpoint resource. + +:::tip +If a reservation used to succeed and now reports missing resources, it is often because the search engine has fallen out of sync with the database. Re-index the search engine before investigating further — see [Search engine is not in sync with the database](./unable-to-locate-a-resource.md#search-engine-is-not-in-sync-with-the-database). +::: + +### When matching resources exist but are reserved + +The detailed **View Details** diagnostic appears **only** when there are truly unresolvable requirements — requirements with no matching resource in the domain. + +If, instead, matching resources *do* exist but are all currently reserved by other sandboxes (a conflict-only failure), CloudShell does **not** show the detailed diagnostic. It shows the standard **conflict resolver** dialog, which lists each conflicting resource and who is using it until when. From there you can wait for the resources to free up, choose a different time slot, or, if permitted, **Reserve with conflicts**. + +:::note +Because these two paths are distinct, not every failed reservation shows the **View Details** diagnostic. A reservation that fails purely on reserved (but existing) resources will surface the conflict resolver dialog rather than the resolution breakdown. +::: From 1184df554058b5dc61b08ea5c4a1e8b82b7f6b76 Mon Sep 17 00:00:00 2001 From: "QUALISYSTEMS\\nahum-t" Date: Mon, 27 Jul 2026 11:19:26 +0300 Subject: [PATCH 2/2] Add UndeployApps to spellcheck wordlist Co-Authored-By: Claude Opus 4.8 (1M context) --- .wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.wordlist.txt b/.wordlist.txt index cea031af14..431bf53482 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1647,3 +1647,4 @@ undeploy undeploys paginated pagination +UndeployApps