Implement open

This commit is contained in:
Blue 2025-12-03 17:13:41 -08:00
parent 02abdcd90e
commit f7c8778c83
6 changed files with 57 additions and 36 deletions

View File

@ -31,11 +31,6 @@ WSLAContainer::WSLAContainer(WSLAVirtualMachine* parentVM, ServiceRunningProcess
{
}
const std::string& WSLAContainer::Name() const noexcept
{
return m_name;
}
const std::string& WSLAContainer::Image() const noexcept
{
return m_image;

View File

@ -35,7 +35,6 @@ public:
IFACEMETHOD(GetInitProcess)(_Out_ IWSLAProcess** process) override;
IFACEMETHOD(Exec)(_In_ const WSLA_PROCESS_OPTIONS* Options, _Out_ IWSLAProcess** Process, _Out_ int* Errno) override;
const std::string& Name() const noexcept;
const std::string& Image() const noexcept;
static Microsoft::WRL::ComPtr<WSLAContainer> Create(const WSLA_CONTAINER_OPTIONS& Options, WSLAVirtualMachine& parentVM);

View File

@ -228,16 +228,23 @@ try
THROW_IF_FAILED(container.CopyTo(__uuidof(IWSLAContainer), (void**)Container));
m_containers.emplace_back(std::move(container));
m_containers.emplace(containerOptions->Name, std::move(container));
return S_OK;
}
CATCH_RETURN();
HRESULT WSLASession::OpenContainer(LPCWSTR Name, IWSLAContainer** Container)
HRESULT WSLASession::OpenContainer(LPCSTR Name, IWSLAContainer** Container)
try
{
return E_NOTIMPL;
std::lock_guard lock{m_lock};
auto it = m_containers.find(Name);
RETURN_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_containers.end(), "Container not found: '%hs'", Name);
it->second.CopyTo(__uuidof(IWSLAContainer), (void**)Container);
return S_OK;
}
CATCH_RETURN();
HRESULT WSLASession::ListContainers(WSLA_CONTAINER** Containers, ULONG* Count)
try
@ -250,11 +257,11 @@ try
auto output = wil::make_unique_cotaskmem<WSLA_CONTAINER[]>(m_containers.size());
size_t index = 0;
for (const auto& e : m_containers)
for (const auto& [name, container] : m_containers)
{
THROW_HR_IF(E_UNEXPECTED, strcpy_s(output[index].Image, e->Image().c_str()) != 0);
THROW_HR_IF(E_UNEXPECTED, strcpy_s(output[index].Name, e->Name().c_str()) != 0);
THROW_IF_FAILED(e->GetState(&output[index].State));
THROW_HR_IF(E_UNEXPECTED, strcpy_s(output[index].Image, container->Image().c_str()) != 0);
THROW_HR_IF(E_UNEXPECTED, strcpy_s(output[index].Name, name.c_str()) != 0);
THROW_IF_FAILED(container->GetState(&output[index].State));
index++;
}

View File

@ -38,7 +38,7 @@ public:
// Container management.
IFACEMETHOD(CreateContainer)(_In_ const WSLA_CONTAINER_OPTIONS* Options, _Out_ IWSLAContainer** Container) override;
IFACEMETHOD(OpenContainer)(_In_ LPCWSTR Name, _In_ IWSLAContainer** Container) override;
IFACEMETHOD(OpenContainer)(_In_ LPCSTR Name, _In_ IWSLAContainer** Container) override;
IFACEMETHOD(ListContainers)(_Out_ WSLA_CONTAINER** Images, _Out_ ULONG* Count) override;
// VM management.
@ -63,7 +63,7 @@ private:
Microsoft::WRL::ComPtr<WSLAVirtualMachine> m_virtualMachine;
std::wstring m_displayName;
std::filesystem::path m_storageVhdPath;
std::vector<Microsoft::WRL::ComPtr<WSLAContainer>> m_containers;
std::map<std::string, Microsoft::WRL::ComPtr<WSLAContainer>> m_containers;
std::mutex m_lock;
// TODO: Add container tracking here. Could reuse m_lock for that.

View File

@ -284,7 +284,7 @@ interface IWSLASession : IUnknown
// Container management.
HRESULT CreateContainer([in] const struct WSLA_CONTAINER_OPTIONS* Options, [out] IWSLAContainer** Container);
HRESULT OpenContainer([in] LPCWSTR Name, [out] IWSLAContainer** Container);
HRESULT OpenContainer([in] LPCSTR Name, [out] IWSLAContainer** Container);
HRESULT ListContainers([out, size_is(, *Count)] struct WSLA_CONTAINER** Images, [out] ULONG* Count);
// Create a process at the VM level. This is meant for debugging.

View File

@ -1154,30 +1154,50 @@ class WSLATests
}
};
// Create a stuck container.
WSLAContainerLauncher launcher(
"debian:latest", "test-container-1", "/bin/cat", {}, {}, ProcessFlags::Stdin | ProcessFlags::Stdout | ProcessFlags::Stderr);
{
// Validate that the container list is initially empty.
expectContainerList({});
auto container = launcher.Launch(*session);
// Create a stuck container.
WSLAContainerLauncher launcher(
"debian:latest", "test-container-1", "/bin/cat", {}, {}, ProcessFlags::Stdin | ProcessFlags::Stdout | ProcessFlags::Stderr);
// Verify that the container is in running state.
VERIFY_ARE_EQUAL(container.State(), WslaContainerStateRunning);
expectContainerList({{"test-container-1", "debian:latest", WslaContainerStateRunning}});
auto container = launcher.Launch(*session);
// Kill the container init process and expect it to be in exited state.
auto initProcess = container.GetInitProcess();
initProcess.Get().Signal(9);
// Verify that the container is in running state.
VERIFY_ARE_EQUAL(container.State(), WslaContainerStateRunning);
expectContainerList({{"test-container-1", "debian:latest", WslaContainerStateRunning}});
// Wait for the process to actually exit.
wsl::shared::retry::RetryWithTimeout<void>(
[&]() {
initProcess.GetExitState(); // Throw if the process hasn't exited yet.
},
std::chrono::milliseconds{100},
std::chrono::seconds{30});
// Kill the container init process and expect it to be in exited state.
auto initProcess = container.GetInitProcess();
initProcess.Get().Signal(9);
// Expect the container to be in exited state.
VERIFY_ARE_EQUAL(container.State(), WslaContainerStateExited);
expectContainerList({{"test-container-1", "debian:latest", WslaContainerStateExited}});
// Wait for the process to actually exit.
wsl::shared::retry::RetryWithTimeout<void>(
[&]() {
initProcess.GetExitState(); // Throw if the process hasn't exited yet.
},
std::chrono::milliseconds{100},
std::chrono::seconds{30});
// Expect the container to be in exited state.
VERIFY_ARE_EQUAL(container.State(), WslaContainerStateExited);
expectContainerList({{"test-container-1", "debian:latest", WslaContainerStateExited}});
// Open a new reference to the same container.
wil::com_ptr<IWSLAContainer> sameContainer;
VERIFY_SUCCEEDED(session->OpenContainer("test-container-1", &sameContainer));
// Verify that the state matches.
WSLA_CONTAINER_STATE state{};
VERIFY_SUCCEEDED(sameContainer->GetState(&state));
VERIFY_ARE_EQUAL(state, WslaContainerStateExited);
}
// Verify that trying to open a non existing container fails.
{
wil::com_ptr<IWSLAContainer> sameContainer;
VERIFY_ARE_EQUAL(session->OpenContainer("does-not-exist", &sameContainer), HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
}
}
};