diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cdc78aa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +1.1.0 (23 Jul 2013) +------------------- + +* Exposed XenAPI HTTP calls in the PowerShell SDK. +* Removed PowerShell Snap-In installer. Ship as PowerShell Module instead. +* Added PowerShell example script HttpTest.ps1. Updated AutomatedTestCore.ps1. +* Added C# overload for Host.apply_edition. + +1.0.0 (17 Jun 2013) +------------------- + +* First public release. diff --git a/ChangeLog.md b/ChangeLog.md deleted file mode 100644 index 87547ab..0000000 --- a/ChangeLog.md +++ /dev/null @@ -1,4 +0,0 @@ -1.0.0 (17-Jun-2013) -------------------- - -* First public release. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..9084fa2 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.1.0 diff --git a/mk/powershell.sh b/mk/powershell.sh index 09651ed..48be1fb 100755 --- a/mk/powershell.sh +++ b/mk/powershell.sh @@ -51,8 +51,9 @@ then remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign.bat XenServerPowerShell.dll 'Citrix XenServer PowerShell Module'" remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign-ps.bat Initialize-Environment.ps1" remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign-ps.bat AutomatedTestCore.ps1" + remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign-ps.bat HttpTest.ps1" remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign-ps.bat XenServer.format.ps1xml" remote_cmd_passwd2 "cd ${TMPDIR} && ${CMD_EXEC} sign-ps.bat XenServer.types.ps1xml" fi -EXTRA_FILES="AutomatedTestCore.ps1 Initialize-Environment.ps1 XenServer.format.ps1xml XenServer.types.ps1xml" +EXTRA_FILES="AutomatedTestCore.ps1 HttpTest.ps1 Initialize-Environment.ps1 XenServer.format.ps1xml XenServer.types.ps1xml" diff --git a/powershell/XenServerPSModule.psd1 b/powershell/XenServerPSModule.psd1 index 04bb123..90c125f 100644 --- a/powershell/XenServerPSModule.psd1 +++ b/powershell/XenServerPSModule.psd1 @@ -60,6 +60,7 @@ FormatsToProcess = @('XenServer.format.ps1xml') FileList = @('about_XenServer.help.txt', 'AutomatedTestCore.ps1', 'CookComputing.XmlRpcV2.dll', + 'HttpTest.ps1', 'Initialize-Environment.ps1', 'LICENSE.CookComputing.XmlRpcV2', 'LICENSE.txt', diff --git a/powershell/common_functions.ml b/powershell/common_functions.ml index 20a6e34..db3cba8 100644 --- a/powershell/common_functions.ml +++ b/powershell/common_functions.ml @@ -210,7 +210,7 @@ and cut_msg_name message_name fn_type = end else if (fn_type = "Remove") then begin - if (name_len > 10)&& (String.sub message_name 0 10) = "RemoveFrom" then + if (name_len > 10) && (String.sub message_name 0 10) = "RemoveFrom" then String.sub message_name 10 (name_len - 10) else if (name_len > 6) && (String.sub message_name 0 6) = "Remove" then String.sub message_name 6 (name_len - 6) @@ -227,3 +227,41 @@ and has_uuid x = and has_name x = DU.obj_has_get_by_name_label x + +and get_http_action_verb name meth = + let parts = String.split '_' name in + if (List.exists (fun x -> x = "import") parts) then "Import" + else if (List.exists (fun x -> x = "export") parts) then "Export" + else if (List.exists (fun x -> x = "get") parts) then "Receive" + else if (List.exists (fun x -> x = "put") parts) then "Send" + else + match meth with + | Get -> "Receive" + | Put -> "Send" + | _ -> assert false + +and get_common_verb_category verb = + match verb with + | "Import" + | "Export" -> "VerbsData" + | "Receive" + | "Send" -> "VerbsCommunications" + | _ -> assert false + +and get_http_action_stem name = + let parts = String.split '_' name in + let filtered = List.filter trim_http_action_stem parts in + let trimmed = String.concat "_" filtered in + match trimmed with + | "" -> pascal_case_ "vm" + | _ -> pascal_case_ trimmed + +and trim_http_action_stem x = + match x with + | "get" + | "put" + | "import" + | "export" + | "download" + | "upload" -> false + | _ -> true diff --git a/powershell/gen_powershell_binding.ml b/powershell/gen_powershell_binding.ml index 39782e1..484eb4c 100644 --- a/powershell/gen_powershell_binding.ml +++ b/powershell/gen_powershell_binding.ml @@ -91,6 +91,133 @@ let generated x = let rec main() = List.iter (fun x -> if generated x then gen_binding x) classes; gen_xenref_converters classes; + List.iter gen_http_action + (List.filter (fun (_, (_, _, sdk, _, _, _)) -> sdk) http_actions) + +(****************) +(* Http actions *) +(****************) + +and gen_http_action action = + match action with (name, (meth, uri, _, args, _, _)) -> + let commonVerb = get_http_action_verb name meth in + let verbCategory = get_common_verb_category commonVerb in + let stem = get_http_action_stem name in + let content = sprintf "%s + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation; +using System.Net; +using System.Text; + +using XenAPI; + +namespace Citrix.XenServer.Commands +{ + [Cmdlet(%s.%s, \"Xen%s\"%s)] + [OutputType(typeof(void))] + public class %sXen%sCommand : XenServerHttpCmdlet + { + #region Cmdlet Parameters +%s%s + #endregion + + #region Cmdlet Methods + + protected override void ProcessRecord() + { + GetSession(); +%s + RunApiCall(() => %s); + } + + #endregion + } +}\n" Licence.bsd_two_clause + verbCategory commonVerb stem (gen_should_process_http_decl meth) + commonVerb stem + (gen_progress_tracker meth) + (gen_arg_params args) + (gen_should_process_http meth uri) + (gen_http_action_call action) +in + write_file (sprintf "%s-Xen%s.cs" commonVerb stem) content + +and gen_should_process_http_decl meth = + match meth with + | Put -> ", SupportsShouldProcess = true" + | Get -> ", SupportsShouldProcess = false" + | _ -> assert false + +and gen_should_process_http meth uri = + match meth with + | Put -> sprintf " + if (!ShouldProcess(\"%s\")) + return;\n" uri + | _ -> "" + +and gen_progress_tracker meth = + match meth with + | Get -> " + [Parameter] + public HTTP.DataCopiedDelegate DataCopiedDelegate { get; set; }\n" + | Put -> " + [Parameter] + public HTTP.UpdateProgressDelegate ProgressDelegate { get; set; }\n" + | _ -> assert false + +and gen_arg_params args = + match args with + | [] -> "" + | hd::tl -> sprintf "%s%s" (gen_arg_param hd) (gen_arg_params tl) + +and gen_arg_param = function + | String_query_arg x -> sprintf " + [Parameter%s] + public string %s { get; set; }\n" + (if (String.lowercase x) = "uuid" then + "(ValueFromPipelineByPropertyName = true)" + else "") + (pascal_case_ x) + | Int64_query_arg x -> sprintf " + [Parameter] + public long %s { get; set; }\n" (pascal_case_ x) + | Bool_query_arg x -> + let y = if x = "host" then "is_host" else x in + sprintf " + [Parameter] + public bool %s { get; set; }\n" (pascal_case_ y) + | Varargs_query_arg -> sprintf " + /// + /// Alternate names & values + /// + [Parameter] + public string[] Args { get; set; }\n" + +and gen_http_action_call (name, (meth, _, _, args, _, _)) = + let progressTracker = match meth with + | Get -> "DataCopiedDelegate" + | Put -> "ProgressDelegate" + | _ -> assert false in + sprintf "XenAPI.HTTP_actions.%s(%s, + CancellingDelegate, TimeoutMs, XenHost, Proxy, Path, TaskRef, + session.opaque_ref%s)" + name progressTracker (gen_call_arg_params args) + +and gen_call_arg_params args = + match args with + | [] -> "" + | hd::tl -> sprintf "%s%s" (gen_call_arg_param hd) (gen_call_arg_params tl) + +and gen_call_arg_param = function + | String_query_arg x -> sprintf ", %s" (pascal_case_ x) + | Int64_query_arg x -> sprintf ", %s" (pascal_case_ x) + | Bool_query_arg x -> + let y = if x = "host" then "is_host" else x in + sprintf ", %s" (pascal_case_ y) + | Varargs_query_arg -> sprintf ", Args" (***********************************) @@ -223,7 +350,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Get, \"Xen%s\", DefaultParameterSetName = \"Ref\")] + [Cmdlet(VerbsCommon.Get, \"Xen%s\", DefaultParameterSetName = \"Ref\", SupportsShouldProcess = false)] [OutputType(typeof(%s[]))] public class GetXen%sCommand : XenServerCmdlet {\n" @@ -341,7 +468,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.New, \"Xen%s\", SupportsShouldProcess=true)] + [Cmdlet(VerbsCommon.New, \"Xen%s\", SupportsShouldProcess = true)] [OutputType(typeof(%s))]%s [OutputType(typeof(void))] public class NewXen%sCommand : XenServerCmdlet @@ -562,7 +689,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Remove, \"Xen%s\", SupportsShouldProcess=true)] + [Cmdlet(VerbsCommon.Remove, \"Xen%s\", SupportsShouldProcess = true)] [OutputType(typeof(%s))]%s [OutputType(typeof(void))] public class RemoveXen%s : XenServerCmdlet @@ -639,7 +766,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Remove, \"Xen%sProperty\", SupportsShouldProcess=true)] + [Cmdlet(VerbsCommon.Remove, \"Xen%sProperty\", SupportsShouldProcess = true)] [OutputType(typeof(%s))]%s public class RemoveXen%sProperty : XenServerCmdlet { @@ -709,7 +836,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Set, \"Xen%s\", SupportsShouldProcess=true)] + [Cmdlet(VerbsCommon.Set, \"Xen%s\", SupportsShouldProcess = true)] [OutputType(typeof(%s))]%s [OutputType(typeof(void))] public class SetXen%s : XenServerCmdlet @@ -780,7 +907,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Add, \"Xen%s\", SupportsShouldProcess=true)] + [Cmdlet(VerbsCommon.Add, \"Xen%s\", SupportsShouldProcess = true)] [OutputType(typeof(%s))]%s [OutputType(typeof(void))] public class AddXen%s : XenServerCmdlet @@ -850,7 +977,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsLifecycle.Invoke, \"Xen%s\", SupportsShouldProcess=true)] + [Cmdlet(VerbsLifecycle.Invoke, \"Xen%s\", SupportsShouldProcess = true)] public class InvokeXen%s : XenServerCmdlet { #region Cmdlet Parameters @@ -924,7 +1051,7 @@ using XenAPI; namespace Citrix.XenServer.Commands { - [Cmdlet(VerbsCommon.Get, \"Xen%sProperty\", SupportsShouldProcess=false)] + [Cmdlet(VerbsCommon.Get, \"Xen%sProperty\", SupportsShouldProcess = false)] public class GetXen%sProperty : XenServerCmdlet { #region Cmdlet Parameters diff --git a/powershell/samples/HttpTest.ps1 b/powershell/samples/HttpTest.ps1 new file mode 100644 index 0000000..e6e79d6 --- /dev/null +++ b/powershell/samples/HttpTest.ps1 @@ -0,0 +1,101 @@ +# +# Copyright (c) Citrix Systems, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2) Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +Param([Parameter(Mandatory=$true)][String]$svr, + [Parameter(Mandatory=$true)][String]$usr, + [Parameter(Mandatory=$true)][String]$pwd, + [Parameter(Mandatory=$true)][String]$patchPath) + +### Connect to a server + +Connect-XenServer -Server $svr -UserName $usr -Password $pwd + + +### Create a VM + +$template = @(Get-XenVM -Name 'Windows XP*' | where {$_.is_a_template})[0] + +Invoke-XenVM -VM $template -XenAction Clone -NewName "testVM" -Async ` + -PassThru | Wait-XenTask -ShowProgress + +$vm = Get-XenVM -Name "testVM" +$sr = Get-XenSR -Ref (Get-XenPool).default_SR +$other_config = $vm.other_config +$other_config["disks"] = $other_config["disks"].Replace('sr=""', 'sr="{0}"' -f $sr.uuid) + +New-XenVBD -VM $vm -VDI $null -Userdevice 3 -Bootable $false -Mode RO ` + -Type CD -Unpluggable $true -Empty $true -OtherConfig @{} ` + -QosAlgorithmType "" -QosAlgorithmParams @{} + +Set-XenVM -VM $vm -OtherConfig $other_config +Invoke-XenVM -VM $vm -XenAction Provision -Async -PassThru | Wait-XenTask -ShowProgress + + +# Export the VM using the DataCopiedDelegate parameter to track bytes received + +$path = $env:TEMP + "\vm.xva" + +$trackDataReceived = [XenAPI.HTTP+DataCopiedDelegate]{ + param($bytes); + Write-Host "Bytes received: $bytes" } + +Export-XenVm -XenHost $svr -Uuid $vm.uuid -Path $path -DataCopiedDelegate $trackDataReceived + +$vm | Remove-XenVM + + +### Import the previously exported VM using the ProgressDelegate parameter to track send progress + +$trackProgress = [XenAPI.HTTP+UpdateProgressDelegate]{ + param($percent); + Write-Progress -Activity "Importing Vm..." -PercentComplete $percent } + +Import-XenVm -XenHost $svr -Path $path -ProgressDelegate $trackProgress + + +### Upload a patch + +$trackProgress = [XenAPI.HTTP+UpdateProgressDelegate]{ + param($percent); + Write-Progress -Activity "Uploading patch..." -PercentComplete $percent } + +Send-XenPoolPatch -XenHost $svr -Path $patchPath + + +### Get host RRDs + +$path = $env:TEMP + "\rrd.xml" +Receive-XenHostRrd -XenHost $svr -Path $path -DataCopiedDelegate $trackDataReceived + + +### Disconnect before finishing + +Get-XenSession | Disconnect-XenServer \ No newline at end of file diff --git a/powershell/src/XenServerHttpCmdlet.cs b/powershell/src/XenServerHttpCmdlet.cs new file mode 100644 index 0000000..7b0e3e8 --- /dev/null +++ b/powershell/src/XenServerHttpCmdlet.cs @@ -0,0 +1,66 @@ +/* + * Copyright (c) Citrix Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +using System; +using System.Collections.Generic; +using System.Management.Automation; +using System.Net; +using System.Text; + +using XenAPI; + +namespace Citrix.XenServer.Commands +{ + public class XenServerHttpCmdlet : XenServerCmdlet + { + #region Cmdlet Parameters + + [Parameter] + public HTTP.FuncBool CancellingDelegate { get; set; } + + [Parameter] + public int TimeoutMs { get; set; } + + [Parameter(Mandatory = true)] + public string XenHost { get; set; } + + [Parameter] + public IWebProxy Proxy { get; set; } + + [Parameter(Mandatory = true)] + public string Path { get; set; } + + [Parameter] + public string TaskRef { get; set; } + + #endregion + } +}