| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | InspectTasks.cpp |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | Implementation of inspection command related execution logic. |
| 12 | --*/ |
| 13 | |
| 14 | #include "Argument.h" |
| 15 | #include "ArgumentConvertedTypes.h" |
| 16 | #include "InspectTasks.h" |
| 17 | #include "InspectModel.h" |
| 18 | #include "ImageService.h" |
| 19 | #include "NetworkService.h" |
| 20 | #include "VolumeService.h" |
| 21 | #include "ContainerService.h" |
| 22 | |
| 23 | namespace wsl::windows::wslc::task { |
| 24 | |
| 25 | using namespace wsl::shared; |
| 26 | using namespace wsl::windows::common; |
| 27 | using namespace wsl::windows::common::string; |
| 28 | using namespace wsl::windows::common::wslutil; |
| 29 | using namespace wsl::windows::wslc::models; |
| 30 | |
| 31 | template <typename TInspectFn> |
| 32 | static bool TryInspect(TInspectFn&& fn, HRESULT notFoundError) |
| 33 | { |
| 34 | try |
| 35 | { |
| 36 | fn(); |
| 37 | return true; |
| 38 | } |
| 39 | catch (const wil::ResultException& ex) |
| 40 | { |
| 41 | auto errorCode = ex.GetErrorCode(); |
| 42 | if (errorCode == notFoundError || errorCode == HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS) || errorCode == E_INVALIDARG) |
| 43 | { |
| 44 | return false; |
| 45 | } |
| 46 | |
| 47 | throw; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | static bool TryInspectImage(wsl::windows::wslc::models::Session& session, const std::string& image, std::optional<wslc_schema::InspectImage>& result) |
| 52 | { |
| 53 | return TryInspect([&]() { result = services::ImageService::Inspect(session, image); }, WSLC_E_IMAGE_NOT_FOUND); |
| 54 | } |
| 55 | |
| 56 | static bool TryInspectContainer( |
| 57 | wsl::windows::wslc::models::Session& session, const std::string& containerId, std::optional<wslc_schema::InspectContainer>& result, bool size) |
| 58 | { |
| 59 | return TryInspect([&]() { result = services::ContainerService::Inspect(session, containerId, size); }, WSLC_E_CONTAINER_NOT_FOUND); |
| 60 | } |
| 61 | |
| 62 | static bool TryInspectNetwork(wsl::windows::wslc::models::Session& session, const std::string& networkName, std::optional<wslc_schema::Network>& result) |
| 63 | { |
| 64 | return TryInspect([&]() { result = services::NetworkService::Inspect(session, networkName); }, WSLC_E_NETWORK_NOT_FOUND); |
| 65 | } |
| 66 | |
| 67 | static bool TryInspectVolume(wsl::windows::wslc::models::Session& session, const std::string& volumeId, std::optional<wslc_schema::InspectVolume>& result) |
| 68 | { |
| 69 | return TryInspect([&]() { result = services::VolumeService::Inspect(session, volumeId); }, WSLC_E_VOLUME_NOT_FOUND); |
| 70 | } |
| 71 | |
| 72 | void Inspect(CLIExecutionContext& context) |
| 73 | { |
| 74 | WI_ASSERT(context.Data.Contains(Data::Session)); |
| 75 | auto& session = context.Data.Get<Data::Session>(); |
| 76 | auto objectIds = context.Args.GetAllValues<ArgType::ObjectId>(); |
| 77 | |
| 78 | nlohmann::json array = nlohmann::json::array(); |
| 79 | auto type = InspectType::All; |
| 80 | if (context.Args.Contains(ArgType::Type)) |
| 81 | { |
| 82 | type = context.Args.GetValue<ArgType::Type>(); |
| 83 | } |
| 84 | |
| 85 | const bool size = context.Args.GetValue<ArgType::Size>(); |
| 86 | |
| 87 | // Only containers carry file size information; every other type warns and continues. |
| 88 | const auto warnSizeIgnored = [&](const wchar_t* objectType) { |
| 89 | if (size) |
| 90 | { |
| 91 | context.Terminal.Error(L"{}\n", Localization::WSLCCLI_InspectSizeIgnoredWarning(objectType)); |
| 92 | } |
| 93 | }; |
| 94 | |
| 95 | for (const auto& objectId : objectIds) |
| 96 | { |
| 97 | auto id = WideToMultiByte(objectId); |
| 98 | std::optional<wslc_schema::InspectContainer> container; |
| 99 | std::optional<wslc_schema::InspectImage> image; |
| 100 | std::optional<wslc_schema::Network> network; |
| 101 | std::optional<wslc_schema::InspectVolume> volume; |
| 102 | |
| 103 | if (WI_IsFlagSet(type, InspectType::Container) && TryInspectContainer(session, id, container, size)) |
| 104 | { |
| 105 | array.push_back(wslc_schema::ToInspectJson(*container)); |
| 106 | } |
| 107 | else if (WI_IsFlagSet(type, InspectType::Image) && TryInspectImage(session, id, image)) |
| 108 | { |
| 109 | warnSizeIgnored(L"image"); |
| 110 | array.push_back(std::move(*image)); |
| 111 | } |
| 112 | else if (WI_IsFlagSet(type, InspectType::Network) && TryInspectNetwork(session, id, network)) |
| 113 | { |
| 114 | warnSizeIgnored(L"network"); |
| 115 | array.push_back(std::move(*network)); |
| 116 | } |
| 117 | else if (WI_IsFlagSet(type, InspectType::Volume) && TryInspectVolume(session, id, volume)) |
| 118 | { |
| 119 | warnSizeIgnored(L"volume"); |
| 120 | array.push_back(std::move(*volume)); |
| 121 | } |
| 122 | else |
| 123 | { |
| 124 | context.Terminal.Error(L"{}\n", Localization::WSLCCLI_ObjectNotFoundError(objectId)); |
| 125 | context.ExitCode = 1; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | // Always print the array, even if it's empty or an error was encountered |
| 130 | context.Terminal.Output(L"{}\n", MultiByteToWide(array.dump(context.Args.GetValue<ArgType::InspectFormat>(c_jsonPrettyPrintIndent)))); |
| 131 | } |
| 132 | } // namespace wsl::windows::wslc::task |