mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-25 03:39:52 +01:00
196 lines
9.1 KiB
C#
196 lines
9.1 KiB
C#
|
/* 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:
|
|||
|
*
|
|||
|
* * Redistributions of source code must retain the above
|
|||
|
* copyright notice, this list of conditions and the
|
|||
|
* following disclaimer.
|
|||
|
* * 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.Diagnostics;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
using System.Xml;
|
|||
|
|
|||
|
using XenAdmin.Core;
|
|||
|
using XenAPI;
|
|||
|
|
|||
|
namespace XenAdmin.Plugins
|
|||
|
{
|
|||
|
internal class XenServerPowershellCmd : ShellCmd
|
|||
|
{
|
|||
|
// TODO: CA:40580: These version numbers are not checked anywhere at the moment, and thus are not documented as part of the plugin spec
|
|||
|
public readonly Version SnapInMinVersion; // optional - "version_min" attribute on the "XenServerPowerShellCmd" tag
|
|||
|
public readonly Version SnapInMaxVersion; // optional - "version_max" attribute on the "XenServerPowerShellCmd" tag
|
|||
|
|
|||
|
public readonly bool Debug; // optional - "debug" attribute on the "XenServerPowerShellCmd" tag
|
|||
|
public readonly string Function; // optional - "function" attribute on the "PowerShellCmd" tag
|
|||
|
|
|||
|
public const string ATT_DEBUG = "debug";
|
|||
|
public const string ATT_VERSION_MIN = "version_min";
|
|||
|
public const string ATT_VERSION_MAX = "version_max";
|
|||
|
public const string ATT_FUNCTION = "function";
|
|||
|
|
|||
|
private const string XEN_PARAM_ARRAY_VAR_NAME = "ObjInfoArray";
|
|||
|
private const string XEN_PARAM_ARRAY_HASH_KEY_URL = "url";
|
|||
|
private const string XEN_PARAM_ARRAY_HASH_KEY_SESSION_REF = "sessionRef";
|
|||
|
private const string XEN_PARAM_ARRAY_HASH_KEY_CLASS = "class";
|
|||
|
private const string XEN_PARAM_ARRAY_HASH_KEY_OBJECT_UUID = "objUuid";
|
|||
|
|
|||
|
private const string USER_PARAM_ARRAY_VAR_NAME = "ParamArray";
|
|||
|
|
|||
|
// This is the parameter to a string.Format call, so the double braces come out as single braces in the PowerShell.
|
|||
|
private const string DebugFunction =
|
|||
|
"function __XenCenter_DebugPlugin {{" +
|
|||
|
" trap [Exception] {{" +
|
|||
|
" write-host $($_.Exception.GetType().FullName); " +
|
|||
|
" write-host $($_.Exception.Message);" +
|
|||
|
" read-host \"[Press Enter to Exit]\" " +
|
|||
|
" }};" +
|
|||
|
" {0};" +
|
|||
|
"}};" +
|
|||
|
"__XenCenter_DebugPlugin";
|
|||
|
|
|||
|
private const string InvokeExpression =
|
|||
|
"Invoke-Expression $([System.String]::Join([System.Environment]::NewLine, (Get-Content -Path \"{0}\"))); {1}";
|
|||
|
|
|||
|
public XenServerPowershellCmd(XmlNode node, List<string> extraParams)
|
|||
|
: base(node, extraParams)
|
|||
|
{
|
|||
|
Debug = Helpers.GetBoolXmlAttribute(node, ATT_DEBUG, false);
|
|||
|
string versionString = Helpers.GetStringXmlAttribute(node, ATT_VERSION_MIN);
|
|||
|
if (versionString != null)
|
|||
|
SnapInMinVersion = new Version(versionString);
|
|||
|
|
|||
|
versionString = Helpers.GetStringXmlAttribute(node, ATT_VERSION_MAX);
|
|||
|
if (versionString != null)
|
|||
|
SnapInMinVersion = new Version(versionString);
|
|||
|
|
|||
|
Function = Helpers.GetStringXmlAttribute(node, ATT_FUNCTION);
|
|||
|
|
|||
|
Registry.CheckXenServerPSSnapIn();
|
|||
|
}
|
|||
|
|
|||
|
public override Process CreateProcess(List<string> procParams, IList<IXenObject> targets)
|
|||
|
{
|
|||
|
Registry.CheckXenServerPSSnapIn();
|
|||
|
string snapin = Registry.XenServerSnapInLocation();
|
|||
|
// execute the initialize script
|
|||
|
// get ourselves in the correct directory
|
|||
|
// put the parameters in the objInfoArray variable
|
|||
|
// exectute the plugin, with debugging if required
|
|||
|
string command = string.Format(
|
|||
|
"& {{" +
|
|||
|
" . \"{0}\";" +
|
|||
|
" {1}" +
|
|||
|
"}}",
|
|||
|
Path.Combine(Path.GetDirectoryName(snapin), "Initialize-Environment.ps1"),
|
|||
|
MakeInvocationExpression(Filename, Function, procParams, Params, targets, Debug));
|
|||
|
|
|||
|
// finally we escape the entire command statement again as it is being passed into the -Command parameter in quotes
|
|||
|
command = EscapeQuotes(EscapeBackSlashes(command));
|
|||
|
|
|||
|
Process proc = new Process();
|
|||
|
proc.StartInfo.FileName = PluginDescriptor.PowerShellExecutable;
|
|||
|
proc.StartInfo.Arguments = string.Format("-PSConsoleFile \"{0}\" -NoLogo -Command \"{1}\"",
|
|||
|
EscapeQuotes(snapin),
|
|||
|
command);
|
|||
|
proc.StartInfo.UseShellExecute = false;
|
|||
|
proc.StartInfo.CreateNoWindow = !Window;
|
|||
|
proc.StartInfo.WindowStyle = !Window ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal;
|
|||
|
return proc;
|
|||
|
}
|
|||
|
|
|||
|
public static string EscapeQuotes(string s)
|
|||
|
{
|
|||
|
// replacing " with \"
|
|||
|
return s.Replace("\"", "\\\"");
|
|||
|
}
|
|||
|
|
|||
|
public static string EscapeBackSlashes(string s)
|
|||
|
{
|
|||
|
// replacing \ with \\
|
|||
|
return s.Replace("\\", "\\\\");
|
|||
|
}
|
|||
|
|
|||
|
public static string MakeInvocationExpression(string filename, string function, IList<string> proc_params, IList<string> extra_params,
|
|||
|
IList<IXenObject> objs, bool debug)
|
|||
|
{
|
|||
|
string expression = string.Format(InvokeExpression,
|
|||
|
Placeholders.Substitute(filename, objs),
|
|||
|
Placeholders.Substitute(function ?? "", objs));
|
|||
|
string xenArrayStatement = XenArrayStatement(proc_params);
|
|||
|
string extraArrayStatement = ExtraArrayStatement(extra_params, objs);
|
|||
|
|
|||
|
return string.Format("cd \"{0}\"; {1} {2} {3};",
|
|||
|
Program.AssemblyDir, xenArrayStatement, extraArrayStatement,
|
|||
|
debug ? string.Format(DebugFunction, expression) : expression);
|
|||
|
}
|
|||
|
|
|||
|
private static string XenArrayStatement(IList<string> procParams)
|
|||
|
{
|
|||
|
// check how many objects we are passing in, each is a set of 4 strings (url, uuid, obj classname, obj uuid)
|
|||
|
int count = (int)(procParams.Count / 4);
|
|||
|
|
|||
|
// now we form a statement that will initialise a powershell array in the format (a,b,c,d),(a2,b2,c2,d2),(a3,b3,c3,d3) e.t.c
|
|||
|
StringBuilder sb = new StringBuilder();
|
|||
|
sb.Append(string.Format("${0}=@(", XEN_PARAM_ARRAY_VAR_NAME));
|
|||
|
for (int i = 0; i < count; i++)
|
|||
|
{
|
|||
|
if (i > 0)
|
|||
|
sb.Append(',');
|
|||
|
int index = i * 4;
|
|||
|
sb.AppendFormat(" @{{{0}=\"{1}\"; {2}=\"{3}\"; {4}=\"{5}\"; {6}=\"{7}\"}}",
|
|||
|
XEN_PARAM_ARRAY_HASH_KEY_URL, EscapeQuotes(EscapeBackSlashes(procParams[index])),
|
|||
|
XEN_PARAM_ARRAY_HASH_KEY_SESSION_REF, EscapeQuotes(EscapeBackSlashes(procParams[index + 1])),
|
|||
|
XEN_PARAM_ARRAY_HASH_KEY_CLASS, EscapeQuotes(EscapeBackSlashes(procParams[index + 2])),
|
|||
|
XEN_PARAM_ARRAY_HASH_KEY_OBJECT_UUID, EscapeQuotes(EscapeBackSlashes(procParams[index + 3])));
|
|||
|
}
|
|||
|
sb.Append(");");
|
|||
|
return sb.ToString();
|
|||
|
}
|
|||
|
|
|||
|
private static string ExtraArrayStatement(IList<string> extraParams, IList<IXenObject> objs)
|
|||
|
{
|
|||
|
// now we form a statement that will initialise a powershell array in the format (a,b,c,d,e,f,g)
|
|||
|
StringBuilder sb = new StringBuilder();
|
|||
|
sb.Append(string.Format("${0}=@(", USER_PARAM_ARRAY_VAR_NAME));
|
|||
|
for (int i = 0; i < extraParams.Count; i++)
|
|||
|
{
|
|||
|
if (i > 0)
|
|||
|
sb.Append(',');
|
|||
|
sb.Append('"');
|
|||
|
sb.Append(EscapeQuotes(EscapeBackSlashes(Placeholders.Substitute(extraParams[i], objs))));
|
|||
|
sb.Append('"');
|
|||
|
}
|
|||
|
sb.Append(");");
|
|||
|
|
|||
|
return sb.ToString();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|