Import a VM into Lab Manager using Orchestrator (part 2)

Posted by: hbr in vCenterserver virtualizationscriptOrchestratorLabmanageresxbash on Print 

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:

tree

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:

image

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:

image

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:

image

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!

Comments (0)Add Comment

Write comment
You must be logged in to post a comment. Please register if you do not have an account yet.

busy