Import a VM into Lab Manager using Orchestrator (part 2)
Posted by: hbr in vCenter, server virtualization, script, Orchestrator, Labmanager, esx, bash on
Nov 10, 2010
This is part 2 of a quick guide to importing a VM into Lab Manager using Orchestrator. In case you missed it, part 1 is available on http://virtuall.eu/blog/import-a-vm-in-lab-manager-using-orchestrator.
Lab Manager import preparation
In the previous blog we selected a VM and exported it to a fileshare. Unfortunately, for Lab Manager to understand this VM export, we need to change it a little. First, we need 2 xml files; a configuration.xml with this content:
<configuration>
<name>container</name>
<export_version>300</export_version>
<template>Y</template>
</configuration>
and a vm.xml with this content:
<VM>
<name>Timprod template</name>
<vmadditions>Y</vmadditions>
<vstype>vmware_esx_30</vstype>
<netinfo>
<netif />
</netinfo>
<bootinfo>
<boot_order>0</boot_order>
<boot_delay>0</boot_delay>
</bootinfo>
</VM>
Now we need to move the content of the export to a directory ’VM0’ so the structure looks like this:
easiest way to do this is to put the two xml files in the same dir as the ‘mv-vm’ script on the esx server and copy them during the VM move. The new ESX script would then look like this:
#!/bin/bash
[ "$1" == "" ] && exit 1
vmx=`vmware-cmd -l | grep -w $1`
[ "$vmx" == "" ] && exit 2
dir=`dirname $vmx`
mnt=/vmfs/volumes/VMFS_Storage01/_clone
vmware-cmd -s unregister $vmx
mount -t cifs –o username=user,password=pwd,workgroup=mydom //server/share/dir/to/put/vm $mnt || exit 3
mkdir $mnt/VM0 –p
mv $dir/* $mnt/VM0 || exit 4
cp configuration.xml $mnt
cp vm.xml $mnt/VM0
rmdir $dir
umount //server/share/dir/to/put/vm
The changes are highlighted in red.
The powershell preparation bit
Once the template on the share is prepared, it’s time to call on some powershell to do the importing. First thing we need to do, is to trust the Lab Manager certificate so we don’t get all kinds of nasty https errors. This bit I got from the internet and you can just copy/paste it. If you have an official Verisign certificate or something, you can skip this part.
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") > $null
$TASource=@'
namespace Local.ToolkitExtensions.Net.CertificatePolicy {
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() { }
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'@
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
Looks quite complex, but the last word should give a pretty good clue what it does.
Next we need to create a SOAP object that can talk to the Lab Manager server. Lab Manager has two interfaces, an internal and an external one. The external is the one that’s documented and can be found at https://yourLM/LabManager/SOAP/LabManager.asmx but if you look at the list of functions, you’ll see it’s quite limited. Besides, there’s no import functions or anything. Those are available through the internal functions available at https://yourLM/LabManager/SOAP/LabManagerInternal.asmx
The list of functions there is huge. And there’s even more than shown here (we’ll get to that later). First, let’s create a some credentials to work with:
$pass = cat C:\users\user1\password.txt | convertto-securestring
$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist "dom\user1",$pass
This part assumes you have a password.txt file in your home directory on the Orchestrator (!) server. There are two things we need to do before this works. The scripts in Orchestrator are run in the context of the local SYSTEM account. The credentials we supply are from some domain account that has access to the Lab Manager server (in this case ‘dom\user1’). To create the password file, we can’t just log in as SYSTEM and create it. Instead we create a small workflow that runs a bit of script to create it for us:
with the next bit of code in the Script tab:
com = new Command ("powershell C:\\users\\user1\\genpwd.ps1")
com.execute(true)
and we put a ‘genpwd.ps1’ file in the homedirectory on the Orchestrator server with this content:
$s=new-object security.securestring
"myPwd".toCharArray()|%{$s.AppendChar($_)}
$s|convertfrom-securestring|out-file C:\users\user1\password.txt
Now if you try to run that, you’ll get an error message from Orchestrator telling you that you’re not allowed to run local commands on it. To fix that we need to put ‘com.vmware.js.allow-local-process=true’ in the file ‘vmo.properties’ that’s in the ‘C:\Program Files\VMware\Infrastructure\Orchestrator\app-server\server\vmo\conf’ directory on your Orchestrator server. Now restart the ‘VMware Orchestrator Server’ service and you’re good to go… almost. We only need tell powershell on Orchestrator to forget about trusting our script and just run it by typing ‘Set-ExecutionPolicy unrestricted’ inside a powershell and now we’re good to go. Try to run the workflow that generates the password file. Once it’s there, it’s time for the next step.
Logging on to Lab Manager with Powershell
Time for some SOAP action. The next bit of code uses the previously created credentials and connects to Lab Manager:
$server = “https://yourLM/LabManager/SOAP/LabManagerInternal.asmx”
function New-ObjectFromProxy {
param($proxy, $proxyAttributeName, $typeName)
$attribute = $proxy | gm | where { $_.Name -eq $proxyAttributeName }
$str = "`$assembly = [" + $attribute.TypeName + "].assembly"
invoke-expression $str
$type = $assembly.getTypes() | where { $_.Name -eq $typeName }
return $assembly.CreateInstance($type)
}
$proxy = New-WebServiceProxy -Uri $server –UseDefaultCredential
$authHeader = New-ObjectFromProxy -proxy $proxy -proxyAttributeName "AuthenticationHeaderValue" -typeName "AuthenticationHeader"
$authHeader.username = $credential.GetNetworkCredential().UserName
$authHeader.password = $credential.GetNetworkCredential().Password
$authHeader.organizationname = "ENTER ORGNAME HERE"
$authHeader.workspacename = "ENTER WORKSPACE HERE"
$proxy.AuthenticationHeaderValue = $authHeader
So far so good. If all went well you can type ‘$proxy|gm’ for a complete list of all available internal functions. To see what parameters the functions need, type ‘$proxy.functionname’ without the brackets and it will tell you what it expects. Now, one function in particular is interesting at the moment:
PS > $proxy.TemplateImportFromSMB
MemberType : Method
OverloadDefinitions : {int TemplateImportFromSMB(string UNCPath, string dirUsername, string dirPassword, string name, string description, string storageServerName, Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMParameter[] parameterList, bool performGuestCustomization)}
TypeNameOfValue : System.Management.Automation.PSMethod
Value : int TemplateImportFromSMB(string UNCPath, string dirUsername, string dirPassword, string name, string description, string storageServerName, Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMParameter[] parameterList, bool performGuestCustomization)
Name : TemplateImportFromSMB
IsInstance : True
That looks promising, except for one thing. The VMParameter array is not a native type in powershell. To see what that is we can use the Lab Manager server by pointing our browser to "https://yourLM/LabManager/SOAP/LabManagerInternal.asmx?WSDL”. Now we just need to get the definition into powershell. To do that we need a file called "C:\Program Files\VMware\VMware vCenter Lab Manager\WebSrvr\bin\VSLA.UI.dll” from the Lab Manager server and put that somewhere on the server that will run the script, say C:\windows. Now to add it and create some parameters:
[Reflection.Assembly]::LoadFrom("C:\Windows\VSLA.UI.dll")
$vmp = new-object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMParameter
$vmp.parameter_name = "HW_VERSION"
$vmp.parameter_value = 7
$vmp1 = new-object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMParameter
$vmp1.parameter_name = "VCPUCOUNT"
$vmp1.parameter_value = 1$vmp2 = new-object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMParameter
$vmp2.parameter_name = "GUESTOS"
$vmp2.parameter_value = "other"
[Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1r_SOAP_LabManagerInternal_asmx.VMparameter[]] $vmps += $vmp
$vmps += $vmp1
$vmps += $vmp2
Fun, huh? The type you would expect to need is a LabManager.Web.SOAP.VMParameter, but instead the Reflection creates a custom type. But it works so that’s good. To be sure, type ‘$vmps’. It should look like this:
Ok, now it’s time to start the template import! Everything’s set up, so now we only need one command to do that:
$proxy.TemplateImportFromSMB(“//server/share/dir/to/put/vm”, $credential.GetNetworkCredential().UserName, $credential.GetNetworkCredential().Password, "TemplateName", "TemplateDesc", "DataStoreName", $vmps, $FALSE);
Cool! You should now see a new a new template appearing under the ‘VM Templates’ in Lab Manager. You can now deploy it to start using it in configurations:
$id=$proxy.GetTemplateByName("TemplateName")[0].id
# 1 = deploy
# 2 = undeploy
# 7 = publish
# 8 = unpublish
$ret = $proxy.TemplatePerformAction($id,7)
and do all sorts of fun stuff with it with functions like ConfigurationAddMachine etc.
Connect it to Orchestrator
The whole scripting bit is done. Now we just need to connect it to Orchestrator. And that’s pretty straightforward and basically the same as described earlier in this post. Just add a Scriptable element and put the Command and execute line in the Script tab. The whole workflow will look something like this:
This is about as minimized as can be and more checking and validation should be done. Implementing that is all up to your own policy, willingness and what not. If you are having trouble or just need a hint, don’t hesitate and follow up on this post!
