diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw
index de258d29d..5744ee0de 100644
--- a/localization/strings/en-US/Resources.resw
+++ b/localization/strings/en-US/Resources.resw
@@ -2124,6 +2124,10 @@ For privacy information about this product please visit https://aka.ms/privacy.<
Volume not found: '{}'
{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated
+
+ Image '{}' not found.
+ {FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated
+
Missing required option: '{}'
{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated
diff --git a/src/windows/wslc/tasks/ContainerTasks.cpp b/src/windows/wslc/tasks/ContainerTasks.cpp
index 804f54282..336daadac 100644
--- a/src/windows/wslc/tasks/ContainerTasks.cpp
+++ b/src/windows/wslc/tasks/ContainerTasks.cpp
@@ -24,6 +24,7 @@ Module Name:
#include
using namespace wsl::shared;
+using namespace wsl::windows::common;
using namespace wsl::windows::common::string;
using namespace wsl::windows::common::wslutil;
using namespace wsl::windows::wslc::execution;
@@ -31,6 +32,26 @@ using namespace wsl::windows::wslc::models;
using namespace wsl::windows::wslc::services;
namespace wsl::windows::wslc::task {
+
+static bool TryInspectContainer(Session& session, const std::string& containerId, std::optional& inspectData)
+{
+ try
+ {
+ inspectData = ContainerService::Inspect(session, containerId);
+ return true;
+ }
+ catch (const wil::ResultException& ex)
+ {
+ if (ex.GetErrorCode() == WSLC_E_CONTAINER_NOT_FOUND)
+ {
+ PrintMessage(Localization::MessageWslcContainerNotFound(containerId.c_str()), stderr);
+ return false;
+ }
+
+ throw;
+ }
+}
+
void AttachContainer::operator()(CLIExecutionContext& context) const
{
WI_ASSERT(context.Data.Contains(Data::Session));
@@ -71,8 +92,15 @@ void InspectContainers(CLIExecutionContext& context)
std::vector result;
for (const auto& id : containerIds)
{
- auto inspectData = ContainerService::Inspect(session, WideToMultiByte(id));
- result.push_back(inspectData);
+ std::optional inspectData;
+ if (TryInspectContainer(session, WideToMultiByte(id), inspectData))
+ {
+ result.push_back(*inspectData);
+ }
+ else
+ {
+ context.ExitCode = 1;
+ }
}
auto json = ToJson(result, c_jsonPrettyPrintIndent);
diff --git a/src/windows/wslc/tasks/ImageTasks.cpp b/src/windows/wslc/tasks/ImageTasks.cpp
index bba509ee4..e177241a9 100644
--- a/src/windows/wslc/tasks/ImageTasks.cpp
+++ b/src/windows/wslc/tasks/ImageTasks.cpp
@@ -26,12 +26,34 @@ Module Name:
#include
using namespace wsl::shared;
+using namespace wsl::windows::common;
using namespace wsl::windows::common::string;
using namespace wsl::windows::common::wslutil;
using namespace wsl::windows::wslc::execution;
+using namespace wsl::windows::wslc::models;
using namespace wsl::windows::wslc::services;
namespace wsl::windows::wslc::task {
+
+static bool TryInspectImage(Session& session, const std::string& imageId, std::optional& inspectData)
+{
+ try
+ {
+ inspectData = ImageService::Inspect(session, imageId);
+ return true;
+ }
+ catch (const wil::ResultException& ex)
+ {
+ if (ex.GetErrorCode() == WSLC_E_IMAGE_NOT_FOUND)
+ {
+ PrintMessage(Localization::MessageWslcImageNotFound(imageId.c_str()), stderr);
+ return false;
+ }
+
+ throw;
+ }
+}
+
void BuildImage(CLIExecutionContext& context)
{
WI_ASSERT(context.Data.Contains(Data::Session));
@@ -197,8 +219,15 @@ void InspectImages(CLIExecutionContext& context)
std::vector result;
for (const auto& id : imageIds)
{
- auto inspectData = ImageService::Inspect(session, WideToMultiByte(id));
- result.push_back(inspectData);
+ std::optional inspectData;
+ if (TryInspectImage(session, WideToMultiByte(id), inspectData))
+ {
+ result.push_back(*inspectData);
+ }
+ else
+ {
+ context.ExitCode = 1;
+ }
}
auto json = ToJson(result, c_jsonPrettyPrintIndent);
diff --git a/test/windows/wslc/e2e/WSLCE2EContainerInspectTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerInspectTests.cpp
new file mode 100644
index 000000000..f804004c1
--- /dev/null
+++ b/test/windows/wslc/e2e/WSLCE2EContainerInspectTests.cpp
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) Microsoft. All rights reserved.
+
+Module Name:
+
+ WSLCE2EContainerInspectTests.cpp
+
+Abstract:
+
+ This file contains end-to-end tests for WSLC.
+--*/
+
+#include "precomp.h"
+#include "windows/Common.h"
+#include "WSLCExecutor.h"
+#include "WSLCE2EHelpers.h"
+#include
+
+namespace WSLCE2ETests {
+using namespace wsl::shared;
+using namespace wsl::shared::string;
+
+class WSLCE2EContainerInspectTests
+{
+ WSLC_TEST_CLASS(WSLCE2EContainerInspectTests)
+
+ TEST_CLASS_SETUP(ClassSetup)
+ {
+ EnsureImageIsLoaded(DebianImage);
+ return true;
+ }
+
+ TEST_CLASS_CLEANUP(ClassCleanup)
+ {
+ EnsureContainerDoesNotExist(TestContainerName1);
+ EnsureContainerDoesNotExist(TestContainerName2);
+ EnsureImageIsDeleted(DebianImage);
+ return true;
+ }
+
+ TEST_METHOD_SETUP(MethodSetup)
+ {
+ EnsureContainerDoesNotExist(TestContainerName1);
+ EnsureContainerDoesNotExist(TestContainerName2);
+ return true;
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_HelpCommand)
+ {
+ auto result = RunWslc(L"container inspect --help");
+ result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0});
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_MissingContainerId)
+ {
+ auto result = RunWslc(L"container inspect");
+ result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'container-id'\r\n", .ExitCode = 1});
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_ContainerNotFound)
+ {
+ auto result = RunWslc(std::format(L"container inspect {}", TestContainerName1));
+ result.Verify({.Stdout = L"[]\r\n", .Stderr = std::format(L"Container '{}' not found.\r\n", TestContainerName1), .ExitCode = 1});
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_Success)
+ {
+ auto createResult = RunWslc(std::format(L"container create --name {} {}", TestContainerName1, DebianImage.NameAndTag()));
+ createResult.Verify({.Stderr = L"", .ExitCode = 0});
+
+ auto result = RunWslc(std::format(L"container inspect {}", TestContainerName1));
+ result.Verify({.Stderr = L"", .ExitCode = 0});
+ auto inspectData =
+ wsl::shared::FromJson>(result.Stdout.value().c_str());
+ VERIFY_ARE_EQUAL(1u, inspectData.size());
+ VERIFY_ARE_EQUAL(WideToMultiByte(TestContainerName1), inspectData[0].Name);
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_InspectMultiple_Success)
+ {
+ // Create two containers to inspect at the same time
+ auto result = RunWslc(std::format(L"container create --name {} {}", TestContainerName1, DebianImage.NameAndTag()));
+ result.Verify({.Stderr = L"", .ExitCode = 0});
+ result = RunWslc(std::format(L"container create --name {} {}", TestContainerName2, DebianImage.NameAndTag()));
+ result.Verify({.Stderr = L"", .ExitCode = 0});
+
+ // Inspect both containers in the same command
+ result = RunWslc(std::format(L"container inspect {} {}", TestContainerName1, TestContainerName2));
+ result.Verify({.Stderr = L"", .ExitCode = 0});
+ auto inspectData =
+ wsl::shared::FromJson>(result.Stdout.value().c_str());
+ VERIFY_ARE_EQUAL(2u, inspectData.size());
+ VERIFY_ARE_EQUAL(WideToMultiByte(TestContainerName1), inspectData[0].Name);
+ VERIFY_ARE_EQUAL(WideToMultiByte(TestContainerName2), inspectData[1].Name);
+ }
+
+ WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_MixedFoundNotFound)
+ {
+ // Create one container but not the other
+ auto result = RunWslc(std::format(L"container create --name {} {}", TestContainerName1, DebianImage.NameAndTag()));
+ result.Verify({.Stderr = L"", .ExitCode = 0});
+
+ // Inspect both containers in the same command, expecting one to be found and the other to not be found
+ result = RunWslc(std::format(L"container inspect {} {}", TestContainerName1, TestContainerName2));
+ result.Verify({.Stderr = std::format(L"Container '{}' not found.\r\n", TestContainerName2), .ExitCode = 1});
+
+ // Verify found container
+ auto inspectData =
+ wsl::shared::FromJson>(result.Stdout.value().c_str());
+ VERIFY_ARE_EQUAL(1u, inspectData.size());
+ VERIFY_ARE_EQUAL(WideToMultiByte(TestContainerName1), inspectData[0].Name);
+ }
+
+private:
+ const std::wstring TestContainerName1 = L"wslc-e2e-container-inspect-1";
+ const std::wstring TestContainerName2 = L"wslc-e2e-container-inspect-2";
+ const TestImage& DebianImage = DebianTestImage();
+
+ std::wstring GetHelpMessage() const
+ {
+ std::wstringstream output;
+ output << GetWslcHeader() //
+ << GetDescription() //
+ << GetUsage() //
+ << GetAvailableCommands() //
+ << GetAvailableOptions();
+ return output.str();
+ }
+
+ std::wstring GetDescription() const
+ {
+ return Localization::WSLCCLI_ContainerInspectLongDesc() + L"\r\n\r\n";
+ }
+
+ std::wstring GetUsage() const
+ {
+ return L"Usage: wslc container inspect [] \r\n\r\n";
+ }
+
+ std::wstring GetAvailableCommands() const
+ {
+ std::wstringstream commands;
+ commands << L"The following arguments are available:\r\n" //
+ << L" container-id Container ID\r\n" //
+ << L"\r\n";
+ return commands.str();
+ }
+
+ std::wstring GetAvailableOptions() const
+ {
+ std::wstringstream options;
+ options << L"The following options are available:\r\n" //
+ << L" --session Specify the session to use\r\n" //
+ << L" -?,--help Shows help about the selected command\r\n" //
+ << L"\r\n";
+ return options.str();
+ }
+};
+} // namespace WSLCE2ETests
diff --git a/test/windows/wslc/e2e/WSLCE2EImageInspectTests.cpp b/test/windows/wslc/e2e/WSLCE2EImageInspectTests.cpp
index 4601aa423..caeb451c9 100644
--- a/test/windows/wslc/e2e/WSLCE2EImageInspectTests.cpp
+++ b/test/windows/wslc/e2e/WSLCE2EImageInspectTests.cpp
@@ -51,8 +51,7 @@ class WSLCE2EImageInspectTests
WSLC_TEST_METHOD(WSLCE2E_Image_Inspect_ImageNotFound)
{
auto result = RunWslc(std::format(L"image inspect {}", InvalidImage.NameAndTag()));
- auto errorMessage = std::format(L"No such image: {}\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", InvalidImage.NameAndTag());
- result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
+ result.Verify({.Stdout = L"[]\r\n", .Stderr = std::format(L"Image '{}' not found.\r\n", InvalidImage.NameAndTag()), .ExitCode = 1});
}
WSLC_TEST_METHOD(WSLCE2E_Image_Inspect_Success)