Skip to content

Commit

Permalink
Add ViewConsole fake command (no API call exists for this!)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardlawley committed Jun 10, 2016
1 parent f85fb9e commit f4d27e3
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 32 deletions.
6 changes: 3 additions & 3 deletions assets/CommonAssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Reflection;

[assembly: AssemblyVersion("4.8.0.10")]
[assembly: AssemblyFileVersion("4.8.0.10")]
[assembly: AssemblyInformationalVersion("4.8.0.10")]
[assembly: AssemblyVersion("4.8.0.12")]
[assembly: AssemblyFileVersion("4.8.0.12")]
[assembly: AssemblyInformationalVersion("4.8.0.12")]

[assembly: CLSCompliant(true)]
2 changes: 1 addition & 1 deletion build.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
param(
[String] $majorMinor = "4.8.0", # 1.4
[String] $patch = "10", # $env:APPVEYOR_BUILD_VERSION
[String] $patch = "12", # $env:APPVEYOR_BUILD_VERSION
[String] $branch = "master", # $env:APPVEYOR_REPO_BRANCH
[String] $customLogger = "", # C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll
[Switch] $notouch
Expand Down
6 changes: 6 additions & 0 deletions src/CloudStack.Net/APIRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public APIRequest(string command) : this(command, false)

public bool SupportsImpersonation { get; }

/// <summary>
/// If non-null, /api will be removed from the endpoint and this value will be appended
/// </summary>
internal virtual string OverrideEndpoint => null;
internal virtual bool OverrideDecodeResponse => false;

protected IList<T> GetList<T>(string name)
{
if (!Parameters.ContainsKey(name))
Expand Down
2 changes: 2 additions & 0 deletions src/CloudStack.Net/CloudStack.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<Compile Include="CloudStackAPIClient.cs" />
<Compile Include="CloudStackAPIProxy.cs" />
<Compile Include="CloudStackException.cs" />
<Compile Include="CustomResponse.cs" />
<Compile Include="Generated\AccountResponse.cs" />
<Compile Include="Generated\AccountState.cs" />
<Compile Include="Generated\ActivateProject.cs" />
Expand Down Expand Up @@ -792,6 +793,7 @@
<Compile Include="ListResponse.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyExtensions.cs" />
<Compile Include="ViewConsole.cs" />
</ItemGroup>
<ItemGroup>
<None Include="CloudStack.Net.nuspec" />
Expand Down
37 changes: 30 additions & 7 deletions src/CloudStack.Net/CloudStackAPIProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private CloudStackAPIProxy(string serviceUrl)
/// Calculates a HMAC SHA-1 hash of the supplied string.
/// </summary>
/// <param name="toSign">String to sign</param>
/// <param name="ssoKey">Signing private key</param>
/// <param name="secretKey">Signing private key</param>
/// <returns>HMAC SHA-1 signature</returns>
public static string CalcSignature(string toSign, string secretKey)
{
Expand All @@ -74,7 +74,7 @@ public static string CalcSignature(string toSign, string secretKey)
/// Produces a query string with an optional signature from arguments in key/value string form.
/// </summary>
/// <param name="arguments">Command in terms of key/value pairs</param>
/// <param name="ssoKey">Optional secret key if the query is to be signed</param>
/// <param name="secretKey">Optional secret key if the query is to be signed</param>
/// <returns>Http query string including the signature.</returns>
/// <remarks>
/// Reference:
Expand Down Expand Up @@ -207,6 +207,8 @@ public static string SerialiseValue(string name, object value)
public TResponse Request<TResponse>(APIRequest request) where TResponse : new()
{
HttpWebRequest webRequest = CreateRequest(request);
webRequest.Timeout = (int)this.HttpRequestTimeout.TotalMilliseconds;
webRequest.ReadWriteTimeout = (int)this.HttpRequestTimeout.TotalMilliseconds;

try
{
Expand All @@ -218,14 +220,30 @@ public static string SerialiseValue(string name, object value)
using (StreamReader streamReader = new StreamReader(respStrm, Encoding.UTF8))
{
string responseText = streamReader.ReadToEnd();
try
TResponse response;
if (request.OverrideDecodeResponse)
{
return DecodeResponse<TResponse>(responseText);
response = new TResponse();
CustomResponse customResponse = response as CustomResponse;
if (customResponse == null)
{
throw new InvalidOperationException($"{nameof(request.OverrideDecodeResponse)} has been selected, but result does not derive from {nameof(CustomResponse)}");
}
customResponse.DecodeResponse(responseText);
}
catch (FormatException ex)
else
{
throw new FormatException("Could not decode CloudStack API Response", ex);
try
{
response = DecodeResponse<TResponse>(responseText);
}
catch (FormatException ex)
{
throw new FormatException("Could not decode CloudStack API Response", ex);
}
}

return response;
}
}
}
Expand Down Expand Up @@ -336,7 +354,12 @@ private CloudStackException CreateCloudStackException(WebException we, Uri fullU
private HttpWebRequest CreateRequest(APIRequest request)
{
string queryString = CreateQuery(request.Parameters, ApiKey, SecretKey, SessionKey);
var fullUri = new Uri(ServiceUrl + "?" + queryString);
string serviceUrlBase = ServiceUrl;
if (!String.IsNullOrEmpty(request.OverrideEndpoint))
{
serviceUrlBase = serviceUrlBase.Substring(0, serviceUrlBase.Length - "api".Length) + request.OverrideEndpoint;
}
var fullUri = new Uri(serviceUrlBase + "?" + queryString);

HttpWebRequest webRequest = WebRequest.CreateHttp(fullUri);
webRequest.Accept = "application/json;charset=UTF-8";
Expand Down
13 changes: 13 additions & 0 deletions src/CloudStack.Net/CustomResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CloudStack.Net
{
public abstract class CustomResponse
{
public abstract void DecodeResponse(string response);
}
}
62 changes: 62 additions & 0 deletions src/CloudStack.Net/ViewConsole.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CloudStack.Net
{
public class ViewConsoleRequest : APIRequest
{
// client/console?cmd=access&vm=vmid

public ViewConsoleRequest() : base("-ViewConsole-")
{
Parameters.Clear();
Parameters.Add("cmd", "access");
}

/// <summary>
/// the name of the physical network
/// </summary>
public Guid VirtualMachineId
{
get { return GetParameterValue<Guid>("vm"); }
set { SetParameterValue("vm", value); }
}

internal override string OverrideEndpoint => "console";
internal override bool OverrideDecodeResponse => true;
}

public class ViewConsoleResponse : CustomResponse
{
private static Regex _rxResponse = new Regex(@"^<html><title>(?<title>.+)</title><frameset><frame src=""(?<url>.*)""></frame></frameset></html>$", RegexOptions.ExplicitCapture | RegexOptions.Compiled);

public string Name { get; set; }
public string Url { get; set; }

public override void DecodeResponse(string response)
{
Match m = _rxResponse.Match(response);
if (!m.Success)
{
throw new FormatException("Console response was not of the expected format:\n\n" + response);
}

Name = m.Groups["name"].Value;
Url = m.Groups["url"].Value;
}
}

public partial interface ICloudStackAPIClient
{
ViewConsoleResponse ViewConsole(ViewConsoleRequest request);
Task<ViewConsoleResponse> ViewConsoleAsync(ViewConsoleRequest request);
}

public partial class CloudStackAPIClient : ICloudStackAPIClient
{
public ViewConsoleResponse ViewConsole(ViewConsoleRequest request) => _proxy.Request<ViewConsoleResponse>(request);
public Task<ViewConsoleResponse> ViewConsoleAsync(ViewConsoleRequest request) => _proxy.RequestAsync<ViewConsoleResponse>(request);
}
}
55 changes: 34 additions & 21 deletions test/CloudStack.Net.TestClient/MainWindow.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test/CloudStack.Net.TestClient/MainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,5 +267,11 @@ private void ButtonCreateDomain_Click(object sender, EventArgs e)
tests.CreateDomain(domainName);
}
}

private void ButtonViewConsole_Click(object sender, EventArgs e)
{
Tests tests = new Tests(this.WriteToLogBox);
tests.ViewConsole(this.TextBoxVMId.Text);
}
}
}
13 changes: 13 additions & 0 deletions test/CloudStack.Net.TestClient/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,19 @@ internal void StopVirtualMachine(string id, bool force)
}
}

internal void ViewConsole(string id)
{
try
{
var result = _client.ViewConsole(new ViewConsoleRequest { VirtualMachineId = Guid.Parse(id) });
_logWriter($"Console for {result.Name} is available at {result.Url}");
}
catch (System.Exception ex)
{
_logWriter("Error viewing console:" + ex.Message);
}
}

#endregion

#region Volume tests
Expand Down

0 comments on commit f4d27e3

Please sign in to comment.