Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/MIDebugEngine/Microsoft.MIDebugEngine.pkgdef
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
"1"="{A2BBC114-47E4-473F-A49C-69EE89711243}"
; WSL Port supplier
"2"="{267B1341-AC92-44DC-94DF-2EE4205DD17E}"
; Podman Port Supplier
"3"="{D4F2F3A5-6B7C-4E8D-9F0A-1B2C3D4E5F6A}"

; Registration to use lldb with the port suppliers
[$RootKey$\AD7Metrics\Engine\{5D630903-189D-4837-9785-699B05BEC2A9}]
Expand Down Expand Up @@ -83,6 +85,8 @@
"0"="{3FDDF14E-E758-4695-BE0C-7509920432C9}"
; WSL Port supplier
"1"="{267B1341-AC92-44DC-94DF-2EE4205DD17E}"
; Podman Port Supplier
"2"="{D4F2F3A5-6B7C-4E8D-9F0A-1B2C3D4E5F6A}"

[$RootKey$\AD7Metrics\Engine\{5D630903-189D-4837-9785-699B05BEC2A9}\IncompatibleList]
"MI Debug Engine - gdb"="{91744D97-430F-42C1-9779-A5813EBD6AB2}"
Expand Down
48 changes: 45 additions & 3 deletions src/SSHDebugPS/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using liblinux;
using liblinux.Persistence;
using Microsoft.SSHDebugPS.Docker;
using Microsoft.SSHDebugPS.Podman;
using Microsoft.SSHDebugPS.SSH;
using Microsoft.SSHDebugPS.UI;
using Microsoft.SSHDebugPS.Utilities;
Expand All @@ -38,7 +39,7 @@ public static DockerConnection GetDockerConnection(string name, bool supportSSHC
{
string connectionString;

bool success = ShowContainerPickerWindow(IntPtr.Zero, supportSSHConnections, out connectionString);
bool success = ShowContainerPickerWindow(IntPtr.Zero, supportSSHConnections, ContainerRuntimeType.Docker, out connectionString);
if (success)
{
success = DockerConnection.TryConvertConnectionStringToSettings(connectionString, out settings, out remoteConnection);
Expand All @@ -65,6 +66,46 @@ public static DockerConnection GetDockerConnection(string name, bool supportSSHC
}
}

public static PodmanConnection GetPodmanConnection(string name, bool supportSSHConnections)
{
if (string.IsNullOrWhiteSpace(name))
return null;

PodmanContainerTransportSettings settings;
Connection remoteConnection;

ThreadHelper.ThrowIfNotOnUIThread();
if (!PodmanConnection.TryConvertConnectionStringToSettings(name, out settings, out remoteConnection) || settings == null)
{
string connectionString;

bool success = ShowContainerPickerWindow(IntPtr.Zero, supportSSHConnections, ContainerRuntimeType.Podman, out connectionString);
if (success)
{
success = PodmanConnection.TryConvertConnectionStringToSettings(connectionString, out settings, out remoteConnection);
}

if (!success || settings == null)
{
VSMessageBoxHelper.PostErrorMessage(StringResources.Error_ContainerConnectionStringInvalidTitle, StringResources.Error_ContainerConnectionStringInvalidMessage);
return null;
}
}

string displayName = PodmanConnection.CreateConnectionString(settings.ContainerName, remoteConnection?.Name, settings.HostName);
if (PodmanHelper.IsContainerRunning(settings.HostName, settings.ContainerName, remoteConnection))
{
return new PodmanConnection(settings, remoteConnection, displayName);
}
else
{
VSMessageBoxHelper.PostErrorMessage(
StringResources.Error_ContainerUnavailableTitle,
StringResources.Error_ContainerUnavailableMessage.FormatCurrentCultureWithArgs(settings.ContainerName));
return null;
}
}

public static SSHConnection GetSSHConnection(string name)
{
ThreadHelper.ThrowIfNotOnUIThread();
Expand Down Expand Up @@ -146,11 +187,12 @@ public static SSHConnection GetSSHConnection(string name)
/// </summary>
/// <param name="hwnd">Parent hwnd or IntPtr.Zero</param>
/// <param name="supportSSHConnections">SSHConnections are supported</param>
/// <param name="runtimeType">Which container runtime to query</param>
/// <param name="connectionString">[out] connection string obtained by the dialog</param>
public static bool ShowContainerPickerWindow(IntPtr hwnd, bool supportSSHConnections, out string connectionString)
public static bool ShowContainerPickerWindow(IntPtr hwnd, bool supportSSHConnections, ContainerRuntimeType runtimeType, out string connectionString)
{
ThreadHelper.ThrowIfNotOnUIThread("Microsoft.SSHDebugPS.ShowContainerPickerWindow");
ContainerPickerDialogWindow dialog = new ContainerPickerDialogWindow(supportSSHConnections);
ContainerPickerDialogWindow dialog = new ContainerPickerDialogWindow(supportSSHConnections, runtimeType);

if (hwnd == IntPtr.Zero) // get the VS main window hwnd
{
Expand Down
14 changes: 14 additions & 0 deletions src/SSHDebugPS/ContainerRuntimeType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.SSHDebugPS
{
/// <summary>
/// Identifies the container runtime to query when discovering containers.
/// </summary>
public enum ContainerRuntimeType
{
Docker,
Podman
}
}
163 changes: 163 additions & 0 deletions src/SSHDebugPS/ContainerTransportSettingsBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.SSHDebugPS.Utilities;
using System.Diagnostics;

namespace Microsoft.SSHDebugPS
{
internal abstract class ContainerTransportSettingsBase : IPipeTransportSettings
{
protected abstract string SubCommand { get; }
protected abstract string SubCommandArgs { get; }

private readonly string _windowsExe;
private readonly string _unixExe;
private readonly string _hostnameFormat;

internal string HostName { get; private set; }
internal bool HostIsUnix { get; private set; }

public ContainerTransportSettingsBase(string hostname, bool hostIsUnix, string windowsExe, string unixExe, string hostnameFormat)
{
HostIsUnix = hostIsUnix;
_windowsExe = windowsExe;
_unixExe = unixExe;
_hostnameFormat = hostnameFormat;
if (!string.IsNullOrWhiteSpace(hostname))
{
HostName = hostname;
}
else
{
HostName = string.Empty;
}
}

public ContainerTransportSettingsBase(ContainerTransportSettingsBase settings)
: this(settings.HostName, settings.HostIsUnix, settings._windowsExe, settings._unixExe, settings._hostnameFormat)
{ }

// 0 = command parameters (e.g. --host/--url)
// 1 = subcommand (e.g. exec, cp, ps)
// 2 = subcommand parameters
private const string _baseCommandFormat = "{0} {1} {2}";

private string GenerateExeCommandArgs()
{
var hostnameArg = string.Empty;
if (!string.IsNullOrWhiteSpace(this.HostName))
hostnameArg = _hostnameFormat.FormatInvariantWithArgs(this.HostName);

return _baseCommandFormat.FormatInvariantWithArgs(hostnameArg, SubCommand, SubCommandArgs);
}

#region IPipeTransportSettings

public string CommandArgs => GenerateExeCommandArgs();

public string Command => HostIsUnix ? _unixExe : _windowsExe;

#endregion
}

internal abstract class ContainerTargetTransportSettings : ContainerTransportSettingsBase
{
internal string ContainerName { get; private set; }

public ContainerTargetTransportSettings(string hostname, string containerName, bool hostIsUnix, string windowsExe, string unixExe, string hostnameFormat)
: base(hostname, hostIsUnix, windowsExe, unixExe, hostnameFormat)
{
ContainerName = containerName;
}

public ContainerTargetTransportSettings(ContainerTargetTransportSettings settings)
: base(settings)
{
ContainerName = settings.ContainerName;
}

protected override string SubCommand => throw new System.NotImplementedException();
protected override string SubCommandArgs => throw new System.NotImplementedException();
}

internal abstract class ContainerExecSettings : ContainerTargetTransportSettings
{
private bool _runInShell;
private string _commandToExecute;
// 0 = container, 1 = command to execute
private const string _subCommandArgsFormat = "{0} {1}";
private const string _subCommandArgsFormatWithShell = "{0} /bin/sh -c \"{1}\"";
private const string _subCommandArgsFormatWithShellLinuxHost = "{0} /bin/sh -c '{1}'";
private const string _interactiveFlag = "-i ";

private bool _makeInteractive;

public ContainerExecSettings(ContainerTargetTransportSettings settings, string command, bool runInShell, bool makeInteractive = true)
: base(settings)
{
Debug.Assert(!string.IsNullOrWhiteSpace(command), "Exec command cannot be null");
_runInShell = runInShell;
_commandToExecute = command;
_makeInteractive = makeInteractive;
}

protected override string SubCommand => "exec";
protected override string SubCommandArgs
{
get
{
string subCommandFormat = this.HostIsUnix ? _subCommandArgsFormatWithShellLinuxHost : _subCommandArgsFormatWithShell;
// Escape single quotes on Linux so variable resolution does not happen until it is in the container.
string command = this.HostIsUnix ? _commandToExecute.Replace("'", "'\\''") : _commandToExecute;
return (_makeInteractive ? _interactiveFlag : string.Empty) +
(_runInShell ? subCommandFormat : _subCommandArgsFormat).FormatInvariantWithArgs(ContainerName, command);
}
}
}

internal abstract class ContainerCopySettings : ContainerTargetTransportSettings
{
// {0} = container, {1} = source, {2} = destination
private const string _copyFormatToContainer = "{1} {0}:{2}";

private string _sourcePath;
private string _destinationPath;

public ContainerCopySettings(string hostname, string sourcePath, string destinationPath, string containerName, bool hostIsUnix, string windowsExe, string unixExe, string hostnameFormat)
: base(hostname, containerName, hostIsUnix, windowsExe, unixExe, hostnameFormat)
{
_sourcePath = sourcePath;
_destinationPath = destinationPath;
}

public ContainerCopySettings(ContainerTargetTransportSettings settings, string sourcePath, string destinationPath)
: base(settings)
{
_sourcePath = sourcePath;
_destinationPath = destinationPath;
}

protected override string SubCommand => "cp";
protected override string SubCommandArgs => _copyFormatToContainer.FormatInvariantWithArgs(ContainerName, _sourcePath, _destinationPath);
}

internal abstract class ContainerCommandSettings : ContainerTransportSettingsBase
{
private string _cmd;
private string _args;

public ContainerCommandSettings(string hostname, bool hostIsUnix, string windowsExe, string unixExe, string hostnameFormat)
: base(hostname, hostIsUnix, windowsExe, unixExe, hostnameFormat)
{ }

public void SetCommand(string cmd, string args)
{
_cmd = cmd;
_args = args;
}

protected override string SubCommand => _cmd;
protected override string SubCommandArgs => _args;
}
}
Loading
Loading