Skip to content
2 changes: 1 addition & 1 deletion src/windows/common/WSLAProcessLauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ ClientRunningWSLAProcess WSLAProcessLauncher::Launch(IWSLASession& Session)
THROW_HR_MSG(hresult, "Failed to launch process: %hs (commandline: %hs). Errno = %i", m_executable.c_str(), commandLine.c_str(), error);
}

return process.value();
return std::move(process.value());
}

std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> WSLAProcessLauncher::LaunchNoThrow(IWSLASession& Session)
Expand Down
4 changes: 4 additions & 0 deletions src/windows/common/WSLAProcessLauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class RunningWSLAProcess
};

RunningWSLAProcess(std::vector<WSLA_PROCESS_FD>&& fds);
NON_COPYABLE(RunningWSLAProcess);
RunningWSLAProcess(RunningWSLAProcess&&) = default;
RunningWSLAProcess& operator=(RunningWSLAProcess&&) = default;

ProcessResult WaitAndCaptureOutput(DWORD TimeoutMs = INFINITE, std::vector<std::unique_ptr<relay::OverlappedIOHandle>>&& ExtraHandles = {});
virtual wil::unique_handle GetStdHandle(int Index) = 0;
virtual wil::unique_event GetExitEvent() = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/windows/wslaservice/exe/ServiceProcessLauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ class ServiceRunningProcess : public common::RunningWSLAProcess
{
public:
NON_COPYABLE(ServiceRunningProcess);
NON_MOVABLE(ServiceRunningProcess);
// NON_MOVABLE(ServiceRunningProcess);

ServiceRunningProcess(ServiceRunningProcess&&) = default;
ServiceRunningProcess& operator=(ServiceRunningProcess&&) = default;

ServiceRunningProcess(const Microsoft::WRL::ComPtr<WSLAProcess>& process, std::vector<WSLA_PROCESS_FD>&& fds);
wil::unique_handle GetStdHandle(int Index) override;
Expand Down
77 changes: 75 additions & 2 deletions src/windows/wslaservice/exe/WSLAContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ Module Name:

using wsl::windows::service::wsla::WSLAContainer;

const std::string nerdctlPath = "/usr/bin/nerdctl";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: and similar for below

Suggested change
const std::string nerdctlPath = "/usr/bin/nerdctl";
constexpr std::string_view c_nerdctlPath = "/usr/bin/nerdctl"sv;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up using a constexpr const char*, since that makes it easier to add to the command line vectors


// Constants for required default arguments for "nerdctl run..."
static std::vector<std::string> defaultNerdctlRunArgs{
"--pull=never",
"--host=net", // TODO: default for now, change later
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The networking option appears to be incorrect. '--host=net' is not a valid nerdctl option. The correct option should be '--net=host' or '--network=host' for host networking mode.

Suggested change
"--host=net", // TODO: default for now, change later
"--network=host", // Use correct nerdctl option for host networking

Copilot uses AI. Check for mistakes.
"--ulimit nofile=65536:65536"};

HRESULT WSLAContainer::Start()
{
return E_NOTIMPL;
Expand All @@ -38,10 +46,12 @@ HRESULT WSLAContainer::GetState(WSLA_CONTAINER_STATE* State)
return E_NOTIMPL;
}

HRESULT WSLAContainer::GetInitProcess(IWSLAProcess** process)
HRESULT WSLAContainer::GetInitProcess(IWSLAProcess** Process)
try
{
return E_NOTIMPL;
return m_containerProcess.Get().QueryInterface(__uuidof(IWSLAProcess), (void**)Process);
}
CATCH_RETURN();

HRESULT WSLAContainer::Exec(const WSLA_PROCESS_OPTIONS* Options, IWSLAProcess** Process, int* Errno)
try
Expand All @@ -53,3 +63,66 @@ try
return S_OK;
}
CATCH_RETURN();

Microsoft::WRL::ComPtr<WSLAContainer> WSLAContainer::Create(const WSLA_CONTAINER_OPTIONS& containerOptions, WSLAVirtualMachine& parentVM)
{
auto args = WSLAContainer::prepareNerdctlRunCommand(containerOptions);

ServiceProcessLauncher launcher(nerdctlPath, args);
return wil::MakeOrThrow<WSLAContainer>(&parentVM, launcher.Launch(parentVM));
}

std::vector<std::string> WSLAContainer::prepareNerdctlRunCommand(const WSLA_CONTAINER_OPTIONS& options)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
std::vector<std::string> WSLAContainer::prepareNerdctlRunCommand(const WSLA_CONTAINER_OPTIONS& options)
std::vector<std::string> WSLAContainer::PrepareNerdctlRunCommand(const WSLA_CONTAINER_OPTIONS& options)

{
std::vector<std::string> args;

args.push_back("run");
args.insert(args.end(), defaultNerdctlRunArgs.begin(), defaultNerdctlRunArgs.end());
args.push_back("--name");
args.push_back(options.Name);
if (options.ShmSize > 0)
{
args.push_back("--shm-size=" + std::to_string(options.ShmSize) + 'm');
}
if (options.Flags & WSLA_CONTAINER_FLAG_ENABLE_GPU)
{
args.push_back("--gpus");
// TODO: Parse GPU device list from WSLA_CONTAINER_OPTIONS. For now, just enable all GPUs.
args.push_back("all");
// args.push_back(options.GPUOptions.GPUDevices);
}

args.insert(args.end(), {"--ulimit", "nofile=65536:65536"});

for (ULONG i = 0; i < options.InitProcessOptions->CommandLineCount; i++)
{
args.push_back(options.InitProcessOptions->CommandLine[i]);
}
for (ULONG i = 0; i < options.InitProcessOptions->EnvironmentCount; i++)
{
args.push_back(options.InitProcessOptions->Environment[i]);
}
for (ULONG i = 0; i < options.VolumesCount; i++)
{
std::string mountContainerPath;
mountContainerPath = std::string(options.Volumes[i].HostPath) + ":" + std::string(options.Volumes[i].ContainerPath);
if (options.Volumes[i].ReadOnly)
{
mountContainerPath += ":ro";
}
args.insert(args.end(), {"-v", mountContainerPath});
}

args.push_back(options.Image);

if (options.InitProcessOptions->CommandLineCount)
{
args.push_back("--");
}
for (ULONG i = 0; i < options.InitProcessOptions->CommandLineCount; i++)
{
args.push_back(options.InitProcessOptions->CommandLine[i]);
}

return args;
}
12 changes: 12 additions & 0 deletions src/windows/wslaservice/exe/WSLAContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ Module Name:

#pragma once

#include "ServiceProcessLauncher.h"
#include "wslaservice.h"
#include "WSLAVirtualMachine.h"

namespace wsl::windows::service::wsla {

Expand All @@ -23,6 +25,10 @@ class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLAContainer
{
public:
WSLAContainer() = default; // TODO
WSLAContainer(WSLAVirtualMachine* parentVM, ServiceRunningProcess&& containerProcess) :
m_parentVM(parentVM), m_containerProcess(std::move(containerProcess))
{
}
WSLAContainer(const WSLAContainer&) = delete;
WSLAContainer& operator=(const WSLAContainer&) = delete;

Expand All @@ -33,6 +39,12 @@ class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLAContainer
IFACEMETHOD(GetInitProcess)(_Out_ IWSLAProcess** process) override;
IFACEMETHOD(Exec)(_In_ const WSLA_PROCESS_OPTIONS* Options, _Out_ IWSLAProcess** Process, _Out_ int* Errno) override;

static Microsoft::WRL::ComPtr<WSLAContainer> Create(const WSLA_CONTAINER_OPTIONS& Options, WSLAVirtualMachine& parentVM);

private:
ServiceRunningProcess m_containerProcess;
WSLAVirtualMachine* m_parentVM = nullptr;

static std::vector<std::string> prepareNerdctlRunCommand(const WSLA_CONTAINER_OPTIONS& options);
};
} // namespace wsl::windows::service::wsla
10 changes: 5 additions & 5 deletions src/windows/wslaservice/exe/WSLASession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ HRESULT WSLASession::DeleteImage(LPCWSTR Image)
return E_NOTIMPL;
}

HRESULT WSLASession::CreateContainer(const WSLA_CONTAINER_OPTIONS* Options, IWSLAContainer** Container)
HRESULT WSLASession::CreateContainer(const WSLA_CONTAINER_OPTIONS* containerOptions, IWSLAContainer** Container)
try
{
// Basic instanciation for testing.
// TODO: Implement.

auto container = wil::MakeOrThrow<WSLAContainer>();
RETURN_HR_IF_NULL(E_POINTER, containerOptions);
// TODO: Log entrance into the function.
m_containerId++;
auto container = WSLAContainer::Create(*containerOptions, *m_virtualMachine);
container.CopyTo(__uuidof(IWSLAContainer), (void**)Container);

return S_OK;
Expand Down
3 changes: 3 additions & 0 deletions src/windows/wslaservice/exe/WSLASession.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLASession
Microsoft::WRL::ComPtr<WSLAVirtualMachine> m_virtualMachine;
std::wstring m_displayName;
std::mutex m_lock;

std::atomic_int m_containerId = 1;
// TODO: Add container tracking here. Could reuse m_lock for that.
};

} // namespace wsl::windows::service::wsla
10 changes: 9 additions & 1 deletion src/windows/wslaservice/inc/wslaservice.idl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ struct WSLA_PROCESS_OPTIONS
struct WSLA_VOLUME
{
LPCSTR HostPath;
LPCSTR ContainerHostPath;
LPCSTR ContainerPath;
BOOL ReadOnly;
};

struct WSLA_PORT_MAPPING
Expand All @@ -126,6 +127,13 @@ struct WSLA_PORT_MAPPING
USHORT ContainerPort;
};

enum WSLA_CONTAINER_FLAGS
{
WSLA_CONTAINER_FLAG_ENABLE_GPU = 0x0,
WSLA_CONTAINER_FLAG_USE_HOST_NETWORKING = 0x1
} ;


struct WSLA_CONTAINER_OPTIONS
{
LPCSTR Image;
Expand Down
2 changes: 1 addition & 1 deletion test/windows/WSLATests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ class WSLATests
auto [hresult, _, process] = launcher.LaunchNoThrow(*session);
VERIFY_ARE_EQUAL(hresult, expectedError);

return process;
return std::move(process);
};

{
Expand Down
Loading