Commands Visibility and Usability
The Shell driver commands are accessible to CloudShell users via the portal as well as to orchestration scripts running on the sandbox. In this section we’ll explore the different ways in which these commands can be customized in their appearance and behavior. The following customization options will be reviewed:
- Changing the function display name and description
- Specifying display name and descriptions for each parameter
- Optional parameters and default values
- Restricting input to a specific set of possible values
- Adding categories
- Orchestration only commands (hidden commands)
- Defining a connected command (which runs on another resource)
If you haven’t done some already it is recommended to go through the Getting Started tutorial before continuing to get a better understanding of the overall process of creating and using a shell. We also assume you’ve gone through the steps described in the Setting Up the Development IDE section of this guide.
We’ll start by creating a new shell that we’ll use in this example. In the Getting Started tutorial we used the ShellFoundry CLI tool to generate a working shell to get started quickly. In this section we’ll also be using the ShellFoundry to create an example shell, only this time we’ll use a different project template. The resource-clean template is similar to the default template we’ve used previously only it doesn’t contain any example driver functions. This will make it easier for us to really go through the experience of starting from a clean slate.
From the command line, navigate to a folder under which you’ll want the new shell to be created and type in the following:
A new project with an empty driver is created.
Let’s start by creating a function we can experiment on. Open the driver file. The file is named driver.py and is located in the src folder of the shell project. Add the following function to the shell driver class and save it:
We’ve now created a shell with a single command. Similar to the flow covered in the Getting Started tutorial, the next steps would be to create a resource instance of this shell in CloudShell and add it to a sandbox so we can experiment with it. You should refer to the Getting Started tutorial for any question on how to accomplish the three steps below:
- Install the shell by running the following from the shell directory: shellfoundry install
- Create a resource instance from the CloudShell inventory.
- Create a new sandbox and drag the resource instance into it. Open the Commands pane.
At this point the Commands pane should look something like this:
As you can see, we didn’t need to specify any additional details to get our Python functions to be visible as shell commands in the CloudShell sandbox, however the commands appear if a very ‘code’ like manner so our next step would be making them a bit more presentable.
The information on how to display the driver functions in CloudShell is stored in the drivermetadata.xml file located in the driver src directory.
Changing the function display name and description
For the first round of customizations, we’ll work on the user facing function and improve the naming of the command and its parameters as they appear to the user in CloudShell. Open the drivermetadata.xml file and add the following text to it:
Each Command element in the xml above customizes a single python function specified by the Name attribute. The DisplayName and Description attributes determines the name of the command as it appears to the user and the description appearing next to it, respectively. And the Visibility attribute determines which user types (AdminOnly/Everyone) can see the command in the blueprint or sandbox.
Reinstall the Shell in CloudShell by running the following command-line and check the Resource Commands panel again.
The shell commands should now look like this:
Please note that changing the display name of a function will affect only how its visually rendered in the UI. Code trying to execute this command using the CloudShell API will need to still refer to it by the command name.
Specify display name and descriptions for each parameter
You may have noticed that the parameter names still look pretty raw and code like. We might want to customize that as well. We can do that by adding additional nested elements describing the parameters under each command. Update the drivermetadata.xml file as follows:
In the drivermetadata.xml XML, the Parameters element contains a list of Parameter elements, each is responsible for a specific function parameter. The DisplayName and Description attributes will determine the name of the command as it appears to the user and the description appearing next to it, respectively.
After installing the shell again, the parameters for the command will now appear in a more readable format:
Optional parameters and default values
For each of the command parameters, we may want to specify whether that parameter is mandatory for the user to supply, and whether there should be a default value in case the user didn’t enter any value.
In the following example, we will make the first parameter mandatory by setting the Mandatory attribute to True. Users will be required to enter a value for parameters before being able to run the command. The second parameter is optional but now has a default value which we will set using the DefaultValue attribute:
Re-installing the shell will update the commands pane accordingly:
Restricting input to a specific set of possible values
For certain parameters, you might want the user to select between a pre-determined set of values, rather than leave the inputs as a free text entry. To set that up, you need to add that information to the parameter XML:
In the xml above, we’ve specified that the second parameter must be selected out of a specific set of possible values. We did that by adding the Type attribute to the parameter element and seting it as Lookup. To define the possible values, we’ve added the AllowedValues attribute, which sets the possible values for this parameter, represented as a comma separated list. In this case, the possible values are Yes and No. We’ve also changed the default value to conform to the possible options.
After re-installing the shell, the Commands pane now reflects the parameter new value restriction:
As you add more commands to the resource, it can be useful to visually group them into categories and improve the usability of the commands panel. These categories will appear as folders which the user can navigate. To demonstrate this capability, let’s first add additional commands to the shell. Open the driver.py file located in the src directory and add the following two functions:
Grouping together commands under a category is pretty strait forward: Simply add a Category element and nest the relevant commands under it. In this case, we’ve added a category called Operate for the previous operation we’ve implemented and a category named Management for the new save and restore functions:
After re-installing the shell we get the following command panel layout:
Orchestration only commands (hidden commands)
Sometimes, you may wish to create commands that are intended to be used as a part of an orchestration flow, for example to be called during setup, but want these commands to be inaccessible to users [hidden] from the UI. For example, a command that is called during a sandbox’s Setup process. To support this use case, CloudShell supports a special category, the Hidden Commands category, which allows you to omit commands from the web portal UI while allowing them to be invoked via the API.
To demonstrate this capability, let’s first add a new function to our driver class in the driver.py file:
Next, let’s add the special category to the drivermetadata.xml file and nest that command under it:
After re-installing the shell you’ll see the new function doesn’t appear in the Commands pane:
Note that the Visibility attribute we discussed earlier in this article does not apply to commands in this category and will be ignored.
Defining a connected command (which runs on another resource)
In some scenarios, a command that runs on a specific resource logically requires the use of a different resource. These types of commands are called connected commands. They are executed on a resource in CloudShell Portal but in reality run on the connected resource (for example, a power switch) that performs the action.
There are two types of connected commands - power commands and generic connected commands.
- Power commands power on/off a resource and actually run on a power switch
- Generic resource commands may be used to modify a resource’s settings and run on the server that performs the modifications
Note that in CloudShell, the resource containing the connected command and the target resource must be directly connected to each other. If you have a switch resource in between, the connected command will not show on the target resource.
To create a connected command, you need to use a shell based on a template that supports connected commands, currently, only PDU and Generic Resource With Connected Commands. In addition, in that shell’s driver, you will need to define which commands are connected. This is done in the driver’s drivermetadata.xml, as follows:
For power commands, the command must include the
Tags=”power” flag and the driver must include all three power commands (Power On, Power Off and Power Cycle):
And for generic connected commands, you must use a shell that is based on a supporting standard (Generic Resource With Connected Commands) and include the
Tags=remote_connectivity" flag on the command:
To enable intellisense, on the driver.py, include the
ResourceRemoteCommandContext context in the command’s definition:
In this section we reviewed different ways in which its possible to customize the appearance and behavior of commands and command parameters from the user’s perspective. If you have feedback or additional suggestions for features and improvements be sure to post them on our idea box. We’re always looking for new ideas!