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
1 change: 1 addition & 0 deletions src/windows/wslc/services/ContainerModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct ContainerOptions
bool TTY = false;
std::vector<std::string> Ports;
std::vector<std::wstring> Volumes;
std::vector<std::string> Entrypoint;
};

struct CreateContainerResult
Expand Down
6 changes: 6 additions & 0 deletions src/windows/wslc/services/ContainerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ static wsl::windows::common::RunningWSLCContainer CreateInternal(

containerLauncher.SetContainerFlags(containerFlags);

if (!options.Entrypoint.empty())
{
auto entrypoints = options.Entrypoint;
containerLauncher.SetEntrypoint(std::move(entrypoints));
}

auto [result, runningContainer] = containerLauncher.CreateNoThrow(*session.Get());
if (result == WSLC_E_IMAGE_NOT_FOUND)
{
Expand Down
5 changes: 5 additions & 0 deletions src/windows/wslc/tasks/ContainerTasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ void SetContainerOptionsFromArgs(CLIExecutionContext& context)
}
}

if (context.Args.Contains(ArgType::Entrypoint))
{
options.Entrypoint.push_back(WideToMultiByte(context.Args.Get<ArgType::Entrypoint>()));
}

if (context.Args.Contains(ArgType::ForwardArgs))
{
auto const& forwardArgs = context.Args.Get<ArgType::ForwardArgs>();
Expand Down
38 changes: 38 additions & 0 deletions test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class WSLCE2EContainerRunTests
TEST_CLASS_CLEANUP(ClassCleanup)
{
EnsureContainerDoesNotExist(WslcContainerName);
EnsureImageIsDeleted(DebianImage);
return true;
}

Expand Down Expand Up @@ -61,6 +62,43 @@ class WSLCE2EContainerRunTests
VerifyContainerIsListed(WslcContainerName, L"exited");
}

TEST_METHOD(WSLCE2E_Container_Run_Entrypoint)
{
WSL2_TEST_ONLY();

auto result = RunWslc(std::format(L"container run --rm --entrypoint /bin/whoami {}", DebianImage.NameAndTag()));
result.Verify({.Stdout = L"root\n", .Stderr = L"", .ExitCode = 0});
}

TEST_METHOD(WSLCE2E_Container_Run_Entrypoint_And_Arguments)
{
WSL2_TEST_ONLY();

auto result = RunWslc(
std::format(L"container run --rm --entrypoint /bin/echo {} hello from entrypoint with args", DebianImage.NameAndTag()));
result.Verify({.Stdout = L"hello from entrypoint with args\n", .Stderr = L"", .ExitCode = 0});
}

TEST_METHOD(WSLCE2E_Container_Run_Entrypoint_Invalid_Path)
{
WSL2_TEST_ONLY();

auto result = RunWslc(std::format(L"container run --rm --entrypoint /bin/does-not-exist {}", DebianImage.NameAndTag()));
result.Verify(
{.Stdout = L"", .Stderr = L"failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: \"/bin/does-not-exist\": stat /bin/does-not-exist: no such file or directory: unknown\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
Comment thread
AmelBawa-msft marked this conversation as resolved.
}

TEST_METHOD(WSLCE2E_Container_Run_Entrypoint_Detach_Lifecycle)
{
WSL2_TEST_ONLY();

auto result = RunWslc(std::format(
L"container run --name {} -d --entrypoint /bin/sleep {} infinity", WslcContainerName, DebianImage.NameAndTag()));
result.Verify({.Stderr = L"", .ExitCode = 0});

VerifyContainerIsListed(WslcContainerName, L"running");
}

private:
const std::wstring WslcContainerName = L"wslc-test-container";
const TestImage& DebianImage = DebianTestImage();
Expand Down
23 changes: 23 additions & 0 deletions test/windows/wslc/e2e/WSLCE2EHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,28 @@ void EnsureContainerDoesNotExist(const std::wstring& containerName)
}
}

std::vector<wsl::windows::wslc::models::ContainerInformation> ListAllContainers()
{
auto result = RunWslc(L"container list --all --format json");
result.Verify({.Stderr = L"", .ExitCode = 0});
auto jsonOutput = result.GetStdoutOneLine();
return wsl::shared::FromJson<std::vector<wsl::windows::wslc::models::ContainerInformation>>(jsonOutput.c_str());
}

void EnsureImageContainersAreDeleted(const TestImage& image)
{
auto containers = ListAllContainers();
for (const auto& container : containers)
{
auto nameAndTag = wsl::shared::string::WideToMultiByte(image.NameAndTag());
if (container.Image.find(nameAndTag) != std::string::npos)
Comment thread
AmelBawa-msft marked this conversation as resolved.
{
auto result = RunWslc(std::format(L"container remove --force {}", container.Id));
Comment thread
AmelBawa-msft marked this conversation as resolved.
result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 0});
}
}
}

void EnsureImageIsDeleted(const TestImage& image)
{
auto result = RunWslc(L"image list");
Expand All @@ -187,6 +209,7 @@ void EnsureImageIsDeleted(const TestImage& image)
{
if (line.find(image.NameAndTag()) != std::wstring::npos)
{
EnsureImageContainersAreDeleted(image);
auto deleteResult = RunWslc(std::format(L"image delete --force {}", image.NameAndTag()));
deleteResult.Verify({.Stderr = L"", .ExitCode = 0});
break;
Expand Down
3 changes: 3 additions & 0 deletions test/windows/wslc/e2e/WSLCE2EHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Module Name:
#include <docker_schema.h>
#include <chrono>
#include <wslc_schema.h>
#include <ContainerModel.h>

namespace WSLCE2ETests {

Expand Down Expand Up @@ -103,10 +104,12 @@ void VerifyImageIsNotUsed(const TestImage& image);
std::string GetHashId(const std::string& id, bool fullId = false);
wsl::windows::common::wslc_schema::InspectContainer InspectContainer(const std::wstring& containerName);
wsl::windows::common::wslc_schema::InspectImage InspectImage(const std::wstring& imageName);
std::vector<wsl::windows::wslc::models::ContainerInformation> ListAllContainers();

void EnsureContainerDoesNotExist(const std::wstring& containerName);
void EnsureImageIsLoaded(const TestImage& image);
void EnsureImageIsDeleted(const TestImage& image);
void EnsureImageContainersAreDeleted(const TestImage& image);

// Default timeout of 0 will execute once.
template <typename IntervalRep, typename IntervalPeriod, typename TimeoutRep, typename TimeoutPeriod>
Expand Down
Loading