In this section, we’ll learn how to create a shell that declares a static VM as a resource in CloudShell. A static VM is a VM whose lifecycle is not managed through CloudShell sandboxes. For example, a VM that provides critical services or data, like a database, switch or bridge.

The only difference between a static VM resource and a regular resource is that the static VM needs to find the VM in vCenter and create a link between the CloudShell resource and the vCenter resource, thus giving it the vCenter Shell’s capabilities. This is done by modifying the desired shell’s get_inventory command to load the VM’s details into CloudShell, using a CloudShell vCenter resource to access the vCenter server. Using this implementation, CloudShell developers can customize any shell to model static VMs in CloudShell, without altering the shell’s behavior and capabilities.  

In the below example, the get_inventory command gets this information from attributes on the root model (“vCenter Name” and “vCenter VM”). However, a static VM resource can have any modeling in CloudShell and be created by a 1st Gen or 2nd Gen shell as long as the shell’s get_inventory command gets the relevant information and creates the link to the vCenter resource.

static_vm_package/VCenterAutoloadStaticVMDriver/app_discovery/vm_autoload_driver.py view raw
def get_inventory(self, context):
    """
    Will locate vm in vcenter and fill its uuid
    :type context: cloudshell.shell.core.context.ResourceCommandContext
    """
    vcenter_vm_name = context.resource.attributes['vCenter VM']
    vcenter_vm_name = vcenter_vm_name.replace('\\', '/')
    vcenter_name = context.resource.attributes['vCenter Name']

    self.logger.info('start autoloading vm_path: {0} on vcenter: {1}'.format(vcenter_vm_name, vcenter_name))

    with CloudShellSessionContext(context) as cloudshell_session:
        session = cloudshell_session

    vcenter_api_res = session.GetResourceDetails(vcenter_name)
    vcenter_resource = self.model_parser.convert_to_vcenter_model(vcenter_api_res)

    si = None

    try:
        self.logger.info('connecting to vcenter ({0})'.format(vcenter_api_res.Address))
        si = self._get_connection_to_vcenter(self.pv_service, session, vcenter_resource, vcenter_api_res.Address)

        self.logger.info('loading vm uuid')
        vm_loader = VMLoader(self.pv_service)
        uuid = vm_loader.load_vm_uuid_by_name(si, vcenter_resource, vcenter_vm_name)
        self.logger.info('vm uuid: {0}'.format(uuid))
        self.logger.info('loading the ip of the vm')
        ip = self._try_get_ip(self.pv_service, si, uuid, vcenter_resource)
        if ip:
            session.UpdateResourceAddress(context.resource.name, ip)

    except Exception:
        self.logger.exception("Get inventory command failed")
        raise
    finally:
        if si:
            self.pv_service.disconnect(si)

    return self._get_auto_load_response(uuid, vcenter_name, context.resource)

 

Implementing Static VM support in a shell

This procedure assumes you are creating or customizing a 2nd gen shell.

To create/customize a shell to support static VMs:

1) Run the appropriate command in command-line:

     To modify an existing shell:

shellfoundry extend <URL/path-to-shell>

     The path can be a URL to the Shell’s source code on Quali Community’s Integrations page or the filesystem path (prefixed by local:./) to the extracted source code folder.

     To create a new shell based on a specific shell standard:

shellfoundry new <Shell-name> --template <template-name>

2) In the shell’s download folder, open the shell-definition.yaml file in your preferred editor.

3) If you are customizing an existing shell and don’t want to override any existing versions of the shell in CloudShell, update the template version.

4) Locate node-types:.

5) Add the vCenter Name and vCenter VM attributes to the shell. Under the root level model, add the following lines:

properties:
  vCenter Name:
    type: string
    description: vCenter resource to use for authentication against vCenter server.
  vCenter VM:
    type: string
    description: vCenter resource to use for authentication against vCenter server.

6) Also add the lines under the capabilities: section.

7) Save the file.

8) Open the driver.py file.

9) Add the following lines to the beginning of the file:

static_vm_package/VCenterAutoloadStaticVMDriver/app_discovery/vm_autoload_driver.py view raw
from cloudshell.shell.core.driver_context import ApiVmDetails, ApiVmCustomParam
from cloudshell.cp.vcenter.commands.load_vm import VMLoader
from cloudshell.cp.vcenter.common.vcenter.vmomi_service import pyVmomiService
from pyVim.connect import SmartConnect, Disconnect
from cloudshell.cp.vcenter.models.QualiDriverModels import AutoLoadAttribute, AutoLoadCommandContext, AutoLoadDetails
from cloudshell.cp.vcenter.common.model_factory import ResourceModelParser
from cloudshell.cp.vcenter.vm.ip_manager import VMIPManager
from cloudshell.core.logger.qs_logger import get_qs_logger
from cloudshell.cp.vcenter.common.vcenter.task_waiter import SynchronousTaskWaiter
from cloudshell.shell.core.session.cloudshell_session import CloudShellSessionContext

import jsonpickle

     Note that the get_qs_logger is only needed if you decide to implement logging.

10) Add the highlighted code to the get_inventory function:

Will locate vm in vcenter and fill its uuid
        :type context: cloudshell.shell.core.context.ResourceCommandContext
        """
        vcenter_vm_name = context.resource.attributes['vCenter VM']
        vcenter_vm_name = vcenter_vm_name.replace('\\', '/')
        vcenter_name = context.resource.attributes['vCenter Name']

        self.logger.info('start autoloading vm_path: {0} on vcenter: {1}'.format(vcenter_vm_name, vcenter_name))

        with CloudShellSessionContext(context) as cloudshell_session:
            session = cloudshell_session

        vcenter_api_res = session.GetResourceDetails(vcenter_name)
        vcenter_resource = self.model_parser.convert_to_vcenter_model(vcenter_api_res)

     For reference, check out the Static VM example shell’s driver file. Feel free to add logging functionality, as shown in the file.

11) In the same file, add the following function:

static_vm_package/VCenterAutoloadStaticVMDriver/app_discovery/vm_autoload_driver.py view raw
def _get_auto_load_response(self, uuid, vcenter_name, resource):
    vm_details = self._get_vm_details(uuid, vcenter_name, resource)
    # return vm_details
    autoload_atts = [AutoLoadAttribute('', 'VmDetails', vm_details)]
    return AutoLoadDetails([], autoload_atts)

12) Scroll down to the bottom of the file, and add the following code:

static_vm_package/VCenterAutoloadStaticVMDriver/app_discovery/vm_autoload_driver.py view raw
@staticmethod
def _get_vm_details(uuid, vcenter_name, resource):

    vm_details = ApiVmDetails()
    vm_details.UID = uuid
    vm_details.CloudProviderName = vcenter_name
    vm_details.VmCustomParams = []
    str_vm_details = jsonpickle.encode(vm_details, unpicklable=False)
    return str_vm_details




def _get_connection_to_vcenter(self, pv_service, session, vcenter_resource, address):
    password = self._decrypt_password(session, vcenter_resource.password)
    si = pv_service.connect(address,
                            vcenter_resource.user,
                            password,
                            443)
    return si

@staticmethod
def _decrypt_password(session, password):
    return session.DecryptPassword(password).Value

13) Save the file.

14) In command-line, navigate to the shell’s root folder and package the shell.

shellfoundry pack