About Author: Joerg Lew

Posts by Joerg Lew

0

Customize a Virtual Machine

For John’s question in the VMware Communities about customizing a VM here:
http://communities.vmware.com/thread/311899
I took the challenge and created a small example how to customize a Virtual Machine using the CustomizeVM_Task().

The network settings, licensing, domain stuff and so on should come from a sysprep.inf text file.

Creating the proper CustomizationSpecification is really a hard job, especially since a couple of settings are mandatory even if the used information is already given via the SysprepText.

I got help using the API Reference, and the UML charts in Steve Jin’s indispensable book (http://www.amazon.com/VMware-VI-vSphere-SDK-Infrastructure/dp/0137153635 , I cannot mention it often enough… and no, that’s not an affiliate-link…yet… 😀 ), page 242.

When testing it, I got a lot of not helpful errors like “Cannot complete customization”. If you increase the loglevel in vCenter, in the vCenter logs there are a bit more information. Just don’t forget to reset it afterwards to avoid “logflooding”.

At the end I ended up with this code:


var sysprepMime = sysprepFile.getContentAsMimeAttachment();
 var sysprepText = sysprepMime.content
 System.debug("sysprep: " + sysprepText);

//create the custSpec objects
 var custSpec = new VcCustomizationSpec();
 System.debug("custSpec: " + custSpec);
 var myVcCustomizationSysprepText = new VcCustomizationSysprepText() ;
 System.debug("myVcCustomizationSysprepText: " + myVcCustomizationSysprepText);
 myVcCustomizationSysprepText.value = sysprepText //from Resource element above
 custSpec.identity = myVcCustomizationSysprepText;
 System.debug("custSpec.identity: " + custSpec.identity);

//fill the mandatory GlobalIPSettings
 var myVcCustomizationGlobalIPSettings = new VcCustomizationGlobalIPSettings() ;
 custSpec.globalIPSettings = myVcCustomizationGlobalIPSettings;
 System.debug("custSpec.globalIPSettings: " + custSpec.globalIPSettings);

//fill in the NIC-settings-map for one nic with unknownIPGenerator (IP-spec is in sysprep-text):
 var mappingMap = new Array();
 var myVcCustomizationAdapterMapping = new VcCustomizationAdapterMapping() ;
 var myVcCustomizationIPSettings = new VcCustomizationIPSettings() ;
 var myIpGenerator;
 //myIpGenerator = new VcCustomizationUnknownIpGenerator() ;
 //myIpGenerator = new VcCustomizationFixedIp();
 //myIpGenerator.ipAddress = "1.2.3.4";
 myIpGenerator = new VcCustomizationDhcpIpGenerator() ;

myVcCustomizationIPSettings.ip = myIpGenerator;
 myVcCustomizationAdapterMapping.adapter = myVcCustomizationIPSettings;
 System.debug("myVcCustomizationIPSettings.ip:" + myVcCustomizationIPSettings.ip);
 System.debug("myVcCustomizationAdapterMapping.adapter: " + myVcCustomizationAdapterMapping.adapter);
 mappingMap.push(myVcCustomizationAdapterMapping);
 System.debug("mappingMap: " + mappingMap);

//adding map to custSpec
 custSpec.nicSettingMap = mappingMap;

vmToCustomize.customizeVM_Task(custSpec);

Download the full workflow example here: http://www.vcoportal.de/download/workflow/customizeVM.workflow

Customize VM Workflow
Customize VM Workflow
customizeVM.workflow
2.1 KiB
Details...
0

PowerShell & vCO – Call Orchestrator Workflows from PowerShell

UPDATE 6. January 2012:
For an example how to provide inventory objects as input parameters, see this post:
http://www.vcoportal.de/2012/01/how-to-find-inventory-objects-when-calling-vco-workflows-via-the-soap-api/

Execute vCO-Workflow with Powershell:
Via the WebService-API you can execute vCO-workflows automatically. And Powershell 2.0 has a built-in Client for WebServices. So it’s straight forward to start an workflow within a Powershell-Skript:


# Connect to vCO and generate Proxy $vcoWS (-Class and -Namespace for easy stub-object generation later
 # Verbindung zum vCO herstellen und Proxy $vcoWS generieren
 $vcoWS = New-WebServiceProxy -Class VCO -Namespace VCO -Uri http://192.168.215.176:8280/vmware-vmo-webcontrol/webservice?WSDL

# print out result (in every ...)
 # Ergebnis ausgeben (in jedem Schritt...)
 $vcoWS

# Get all Methods of the webserviceProxy
 $vcoWS|get-member|where { $_.MemberType -eq "Method" }

# Find Workflows with name "demoWorkflowWithStringInput" (returns an array!)
 # Workflows mit dem Namen "demoWorkflowWithStringInput" finden (gibt ein Array zurück)
 $workflows = $vcoWS.getWorkflowsWithName("demoWorkflowWithStringInput", "vcoadmin1" , "VMware2010")
 $workflows

# pop first Workflow from resulting array
 # ersten Workflow aus dem Ergebnisarray holen...
 $workflow = $workflows[0]
 $workflow

# print out input Parameters
 $workflow.inParameters

# generate Array with Input PArameters (WorkflowTokenAttribute - Objects)
 $inparams = @()

# fill the array, one entry for each input parameter
 $inparams += New-Object -TypeName VCO.WorkflowTokenAttribute
 $inparams[0].name = "inputString"
 $inparams[0].type = "String"
 $inparams[0].value = "Hello World"

$inparams

# ... and exectue (use $null instead on $inparams if Workflow has no input parameters
 # ... und ausführen
 $workflowToken = $vcoWS.executeWorkflow($workflow.id, "vcoadmin1" , "VMware2010", $inparams)
 $workflowToken

# monitor execution state of Workflow-Token
 # Status der Ausführung überwachen
 do { Start-Sleep -Seconds 2 }
 while ( $vcoWS.getWorkflowTokenStatus(@($workflowToken.id), "vcoadmin1" , "VMware2010") -eq"running")

# get Output-Parameter, when workflow has finished
 #($wftResults is again an array of WorkflowTokenAttribute
 $wftResults = $vcoWS.getWorkflowTokenResult($workflowToken.id, "vcoadmin1", "VMware2010")
 $wftResults

To define input parameters for the workflow, you have to create an array of WorkflowTokenAttribute-Object, each of them with a name, type and value-parameter. (Therefore the -Class and -Namespace parameters when creating the WebService-Proxy)

The output returned from getWorkflowTokenResult are also an array of WorkflowTokenAttrinbute-Objects.

This examples calls a small workflow which just copy an input-string to an output-parameter:

More information about creating a WebService-Client for vCO is in the developer guide:
http://www.vmware.com/pdf/vco_410_developers_guide.pdf#page=245
More information about the New-WebServiceProxy-CmdLet:
http://technet.microsoft.com/en-us/library/dd315258.aspx

# Connect to vCO and generate Proxy $vcoWS (-Class and -Namespace for easy stub-object generation later
# Verbindung zum vCO herstellen und Proxy $vcoWS generieren
$vcoWS = New-WebServiceProxy -Class VCO -Namespace VCO -Uri http://192.168.215.176:8280/vmware-vmo-webcontrol/webservice?WSDL# print out result (in every …)
# Ergebnis ausgeben (in jedem Schritt…)
$vcoWS# Get all Methods of the webserviceProxy
$vcoWS|get-member|where { $_.MemberType -eq “Method” }

# Find Workflows with name “demoWorkflowWithStringInput” (returns an array!)
# Workflows mit dem Namen “demoWorkflowWithStringInput” finden (gibt ein Array zurück)
$workflows = $vcoWS.getWorkflowsWithName(“demoWorkflowWithStringInput”, “vcoadmin1” , “VMware2010”)
$workflows

# pop first Workflow from resulting array
# ersten Workflow aus dem Ergebnisarray holen…
$workflow = $workflows[0]
$workflow

# print out input Parameters
$workflow.inParameters

# generate Array with Input PArameters (WorkflowTokenAttribute – Objects)
$inparams = @()

# fill the array, one entry for each input parameter
$inparams += New-Object -TypeName VCO.WorkflowTokenAttribute
$inparams[0].name = “inputString”
$inparams[0].type = “String”
$inparams[0].value = “Hello World”

$inparams

# … and exectue (use $null instead on $inparams if Workflow has no input parameters
# … und ausführen
$workflowToken = $vcoWS.executeWorkflow($workflow.id, “vcoadmin1” , “VMware2010”, $inparams)
$workflowToken

# monitor execution state of Workflow-Token
# Status der Ausführung überwachen
do { Start-Sleep -Seconds 2 }
while ( $vcoWS.getWorkflowTokenStatus(@($workflowToken.id), “vcoadmin1” , “VMware2010″) -eq”running”)

# get Output-Parameter, when workflow has finished
#($wftResults is again an array of WorkflowTokenAttribute
$wftResults = $vcoWS.getWorkflowTokenResult($workflowToken.id, “vcoadmin1”, “VMware2010”)
$wftResults

0

vCO & PowerShell – Call Powershell-scripts from vCO

Execute Powershell from vCO:

var arg1 = "firstArgument";
 var arg2 = "secondArgument";
 var cmd = "cmd.exe /c powershell.exe " +
 " -Command \". 'c:\\vcoScripts\\somePowershellScript.ps1' '"
 + arg1+ "' '" + arg2 + "' \""
 + " < NUL 2>&1"
 //optional logging + " >>c:/vcoScripts/powershell.log 2>&1"
 ;
 var command = new Command(cmd);
 command.execute(true);

More information:
http://wannemacher.us/?p=346
http://communities.vmware.com/thread/271425

0

Workflow Developer Tools

For convenient viewing of the log files, you can use mtail:
http://ophilipp.free.fr/op_tail.htm
Like the linux tail-command it refreshes the open files and is so a very useful tool to watch the logs while running your workflows.

mtail

If you want an alternative for the built-in script editor
ftp://ftp.mozilla.org/pub/mozilla.org/js/rhino1_6R3.zip
mtail
For convenient viewing of the log files, you can use mtail:
http://ophilipp.free.fr/op_tail.htm
Like the linux tail-command it refreshes the open files and is so a very useful tool to watch the logs while running your workflows.

mtail

Rhino shell
If you want an alternative for the built-in script editor you can use the Rhino-debugger.
Rhino shell
Download the Rhino-package from:
ftp://ftp.mozilla.org/pub/mozilla.org/js/rhino1_6R3.zip
(The links point not to the current version, but to the older 1.6R3-version of Rhino which is used in Orchestrator.)
Unzip, open a command prompt, change to the base-directory and start the debugger with
java -cp js.jar org.mozilla.javascript.tools.debugger.Main
For more information, see the docs at
http://www.mozilla.org/rhino/debugger.html
Unfortunately, there is no integration of this debugger to vCO, so it’s difficult to use it for scripts which uses other Orchestrator objects (which is the fact for most of your scripts, I guess). And you have to copy&paste your code to the vCO-Client. Not very convenient, but maybe helpful to debug some plain JavaScript-elements.
0

Script Debugger

Hmmmmm… finished 🙂
Unfortunately, there is no built-in debugging tool for scripting elements. So no breakpoints, no variable inspection, no tracing.
As a workaround, the only way to see the content of variables is to log them, e.g. to System.debug. Example:
</div>
<div>//vm is an input parameter with type VcVirtualMachine)
 System.debug("vm: " + vm);
 var vmname = vm.name;
 System.debug("vmname: " + vmname);
 var numvcpus = vm.summary.config.numCpu;
 System.debug("VM " + vmname + " has " + numvcpus + " vCPUs");</div>
<div>
Gives following output in script-log.log in $INSTALLDIR\app-server\server\vmo\log:
2011-02-26 17:09:59.010+0100 DEBUG [SCRIPTING_LOG] vm: DynamicWrapper (Instance) : [VcVirtualMachine]-[class com.vmware.vmo.plugin.vi4.model.VimVirtualMachine] -- VALUE : VirtualMachine<vm-128>'lab-db'
2011-02-26 17:09:59.011+0100 DEBUG [SCRIPTING_LOG] vmname: lab-db
2011-02-26 17:09:59.015+0100 DEBUG [SCRIPTING_LOG] VM lab-db has 1 vCPUs
You can see the timestamp (see log4j-config for format), the loglevel DEBUG. For numbers and strings you can see the plain content, for complex data type you can see the type of the variable (e.g. [VcVirtualMachine]-[class com.vmware.vmo.plugin.vi4.model.VimVirtualMachine]) and it’s toString() implementation (VALUE : VirtualMachine’lab-db’).