Dependency Injection pattern in vRO or how to add vNIC to VM in vRA as a custom day 2 action

Learn how to use dependency injection pattern in vRO

Today, we're going to implement a day 2 action for vRA deployment. Custom day 2 actions are a great feature of vRA. They allow us to add almost anything. We will use this feature to add and connect a new vNIC to the deployed VM. We will support both Standard and Distributed switches and all available types of vNICs. Additionally, we'll use native JavaScript, but we'll employ more advanced techniques to make our code more professional. To achieve this, we'll create a networking class that covers all the network parts.

The idea is to create a workflow that will be triggered by the deployment and will call the action element, which will take care of creating and configuring a new network card.

To the VSCode.

Action element

Classes in ES5

In vRO, action elements are JavaScript functions wrapped by vRO. However, these are not regular functions but Immediately-Invoked Function Expressions (IIFE), which run as soon as they are defined. We define an IIFE function inside parentheses and add () to execute that function.

Several preparation steps are needed to add a new network interface card (NIC) to the VM, all related to networking. Therefore, it would be reasonable to create a networking class. It's important to note that vRO's JavaScript engine is Rhino, and its current version supports JavaScript version 5.1, which doesn't support classes natively. Nonetheless, some techniques can help bridge this gap.

More details about classes in Javascript ES5 can be found here.

Network Class

Let’s create a new action element called virtualNetworkManagement and a new class called VirtualNetworkManagement. This class is a function that utilizes the prototype feature of the JS. To create a NIC, we need three preparation steps (methods):

  1. createVirtualDeviceConfigSpec — generate a new config spec for a new device (NIC). The operation will be added, so we want to add a NIC.
  2. createVirtualDeviceConnectInfo — defines the connectivity properties of the NIC. All arguments in that method are booleans.
  3. createVirtualEthernetAdapter — defines the type of the NIC. adapterType is a string that will be passed from the custom form selected by the user.
var VirtualNetworkManagement = /** @class */ (function () {
  VirtualNetworkManagement.prototype.createVirtualDeviceConfigSpec = function (
    operation
  ) {
    var vmConfigSpec = new VcVirtualDeviceConfigSpec();
    vmConfigSpec.operation = operation;
    return vmConfigSpec;
  };
  VirtualNetworkManagement.prototype.createVirtualDeviceConnectInfo = function (
    allowGuestControl,
    connected,
    startConnected
  ) {
    var connectInfo = new VcVirtualDeviceConnectInfo();
    connectInfo.allowGuestControl = allowGuestControl;
    connectInfo.connected = connected;
    connectInfo.startConnected = startConnected;
    return connectInfo;
  };
  VirtualNetworkManagement.prototype.createVirtualEthernetAdapter = function (
    adapterType
  ) {
    switch (adapterType) {
      case "E1000":
        return new VcVirtualE1000();
      case "E1000e":
        return new VcVirtualE1000e();
      case "Vmxnet":
        return new VcVirtualVmxnet();
      case "Vmxnet2":
        return new VcVirtualVmxnet2();
      case "Vmxnet3":
        return new VcVirtualVmxnet3();
      default:
        throw new Error("Unknown adapter type: ".concat(adapterType));
    }
  };
  return VirtualNetworkManagement;
})();

All these are required to create a new vNIC.

Now, we're ready to add a vNIC to the VM. We'll need another method in our class called addVnicToSwitch to do so.

VirtualNetworkManagement.prototype.addVnicToSwitch = function (
  vm,
  switchType,
  adapterType
) {
  var configSpec = new VcVirtualMachineConfigSpec();
  var vmConfigSpecs = [];
  // Create virtual device config spec for adding a new device
  var vmDeviceConfigSpec = this.createVirtualDeviceConfigSpec(
    VcVirtualDeviceConfigSpecOperation.add
  );
  // Create connection info for port group
  var connectInfo = this.createVirtualDeviceConnectInfo(true, true, true);
  // Create virtual ethernet adapter based on adapter type
  var vNetwork = this.createVirtualEthernetAdapter(adapterType);
  if (!vNetwork) throw new Error("Failed to create VirtualEthernetAdapter");
  vNetwork.backing = switchType;
  vNetwork.unitNumber = 0;
  vNetwork.addressType = "Generated";
  vNetwork.wakeOnLanEnabled = true;
  vNetwork.connectable = connectInfo;
  // Add the configured virtual ethernet adapter to device specs
  vmDeviceConfigSpec.device = vNetwork;
  vmConfigSpecs.push(vmDeviceConfigSpec);
  configSpec.deviceChange = vmConfigSpecs;
  System.log("Reconfiguring the virtual machine to add new vNIC");
  try {
    var task = vm.reconfigVM_Task(configSpec);
    System.getModule("com.vmware.library.vc.basic").vim3WaitTaskEnd(
      task,
      true,
      2
    );
  } catch (error) {
    throw new Error("Failed to create vNIC");
  }
};

Dependency Injection Pattern

The most interesting aspect of this method is a variable called switchType (line 17 in addVnicToSwitch method above). Both Standard and Distributed switches share almost identical configurations for all the provided code except for the backing part. For the Standard vSwitch, the vNetwork.backing must be VcVirtualEthernetCardLegacyNetworkBackingInfo, while for the Distributed vSwitch, it must be VcVirtualEthernetCardDistributedVirtualPortBackingInfo.

Read the full story

Sign up now to read the full story and get access to all members-only posts.

Subscribe
Already have an account? Sign in
Great! Next, complete checkout for full access to CloudDepth.
Welcome back! You've successfully signed in.
You've successfully subscribed to CloudDepth.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.

This work by Leonid Belenkiy is licensed under Creative Commons Attribution 4.0 International