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
20 changes: 0 additions & 20 deletions src/shared/inc/JsonUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,24 +185,4 @@ struct adl_serializer<wsl::shared::string::MacAddress>
}
};

#ifdef WIN32
template <>
struct adl_serializer<WSLCVolumeInformation>
{
static void to_json(json& j, const WSLCVolumeInformation& volume)
{
j = json{{"Name", std::string(volume.Name)}, {"Driver", std::string(volume.Driver)}};
}

static void from_json(const json& j, WSLCVolumeInformation& volume)
{
std::string name = j.at("Name").get<std::string>();
std::string driver = j.at("Driver").get<std::string>();

strncpy_s(volume.Name, sizeof(volume.Name), name.c_str(), _TRUNCATE);
strncpy_s(volume.Driver, sizeof(volume.Driver), driver.c_str(), _TRUNCATE);
}
};
#endif

} // namespace nlohmann
13 changes: 13 additions & 0 deletions src/windows/inc/wslc_schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,17 @@ struct NetworkListEntry
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(NetworkListEntry, Id, Name, Driver, Scope, Created, EnableIPv4, EnableIPv6, Internal, Labels);
};

// The volume properties carried from the session to the CLI for "volume list". Values keep their
// native types; the CLI renders the string output.
struct VolumeListEntry
{
std::string Name;
std::string Driver;
std::string Mountpoint;
std::string Scope;
std::map<std::string, std::string> Labels;

NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(VolumeListEntry, Name, Driver, Mountpoint, Scope, Labels);
};

} // namespace wsl::windows::common::wslc_schema
2 changes: 1 addition & 1 deletion src/windows/service/inc/wslc.idl
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ interface IWSLCSession : IUnknown
// Volume management.
HRESULT CreateVolume([in] const WSLCVolumeOptions* Options, [out] WSLCVolumeInformation* VolumeInfo);
HRESULT DeleteVolume([in] LPCSTR Name);
HRESULT ListVolumes([in, unique, size_is(FiltersCount)] const WSLCFilter* Filters, [in] ULONG FiltersCount, [out, size_is(, *Count)] WSLCVolumeInformation** Volumes, [out] ULONG* Count);
HRESULT ListVolumes([in, unique, size_is(FiltersCount)] const WSLCFilter* Filters, [in] ULONG FiltersCount, [out] LPSTR* Output);
HRESULT InspectVolume([in] LPCSTR Name, [out] LPSTR* Output);

HRESULT Authenticate([in] LPCSTR ServerAddress, [in] LPCSTR Username, [in] LPCSTR Password, [out] LPSTR* IdentityToken);
Expand Down
2 changes: 1 addition & 1 deletion src/windows/wslc/core/ExecutionContextData.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace details {
DEFINE_DATA_MAPPING(Containers, std::vector<wsl::windows::wslc::models::ContainerInformation>);
DEFINE_DATA_MAPPING(ContainerOptions, wsl::windows::wslc::models::ContainerOptions);
DEFINE_DATA_MAPPING(Images, std::vector<wsl::windows::wslc::models::ImageInformation>);
DEFINE_DATA_MAPPING(Volumes, std::vector<WSLCVolumeInformation>);
DEFINE_DATA_MAPPING(Volumes, std::vector<wsl::windows::common::wslc_schema::VolumeListEntry>);
DEFINE_DATA_MAPPING(Networks, std::vector<wsl::windows::common::wslc_schema::NetworkListEntry>);
DEFINE_DATA_MAPPING(NetworkEndpointOptions, wsl::windows::wslc::models::NetworkEndpointOptions);
} // namespace details
Expand Down
17 changes: 17 additions & 0 deletions src/windows/wslc/services/VolumeModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,21 @@ struct PruneVolumesResult
ULONGLONG SpaceReclaimed{};
};

// The shape emitted by "volume list --format json"; every value is reported as a string.
struct VolumeOutputInformation
{
std::string Availability;
std::string Driver;
std::string Group;
std::string Labels;
std::string Links;
std::string Mountpoint;
std::string Name;
std::string Scope;
std::string Size;
std::string Status;

NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(VolumeOutputInformation, Availability, Driver, Group, Labels, Links, Mountpoint, Name, Scope, Size, Status);
};

} // namespace wsl::windows::wslc::models
17 changes: 5 additions & 12 deletions src/windows/wslc/services/VolumeService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ void VolumeService::Delete(models::Session& session, const std::string& name)
THROW_IF_FAILED(session.Get()->DeleteVolume(name.c_str()));
}

std::vector<WSLCVolumeInformation> VolumeService::List(models::Session& session, const std::vector<std::pair<std::string, std::string>>& filters)
std::vector<wsl::windows::common::wslc_schema::VolumeListEntry> VolumeService::List(
models::Session& session, const std::vector<std::pair<std::string, std::string>>& filters)
{
std::vector<WSLCFilter> filterEntries;
filterEntries.reserve(filters.size());
Expand All @@ -69,19 +70,11 @@ std::vector<WSLCVolumeInformation> VolumeService::List(models::Session& session,
filterEntries.push_back({.Key = key.c_str(), .Value = value.c_str()});
}

wil::unique_cotaskmem_array_ptr<WSLCVolumeInformation> rawVolumes;
ULONG count = 0;
wil::unique_cotaskmem_ansistring output;
THROW_IF_FAILED(session.Get()->ListVolumes(
filterEntries.empty() ? nullptr : filterEntries.data(), static_cast<ULONG>(filterEntries.size()), &rawVolumes, &count));

std::vector<WSLCVolumeInformation> volumes;
volumes.reserve(count);
for (auto ptr = rawVolumes.get(), end = rawVolumes.get() + count; ptr != end; ++ptr)
{
volumes.push_back(*ptr);
}
filterEntries.empty() ? nullptr : filterEntries.data(), static_cast<ULONG>(filterEntries.size()), &output));

return volumes;
return FromJson<std::vector<wsl::windows::common::wslc_schema::VolumeListEntry>>(output.get());
}

wsl::windows::common::wslc_schema::InspectVolume VolumeService::Inspect(models::Session& session, const std::string& name)
Expand Down
3 changes: 2 additions & 1 deletion src/windows/wslc/services/VolumeService.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ struct VolumeService
{
static WSLCVolumeInformation Create(models::Session& session, const models::CreateVolumeOptions& createOptions);
static void Delete(models::Session& session, const std::string& name);
static std::vector<WSLCVolumeInformation> List(models::Session& session, const std::vector<std::pair<std::string, std::string>>& filters = {});
static std::vector<wsl::windows::common::wslc_schema::VolumeListEntry> List(
models::Session& session, const std::vector<std::pair<std::string, std::string>>& filters = {});
static wsl::windows::common::wslc_schema::InspectVolume Inspect(models::Session& session, const std::string& name);
static models::PruneVolumesResult Prune(
Terminal& terminal, models::Session& session, bool all, const std::vector<std::pair<std::string, std::string>>& filters = {});
Expand Down
37 changes: 36 additions & 1 deletion src/windows/wslc/tasks/VolumeTasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,41 @@ namespace wsl::windows::wslc::task {

constexpr uint32_t c_reclaimedSpacePrecision = 4;

namespace {

// Reported for the fields that only carry a value when volume usage data or swarm cluster
// information is available, neither of which applies here.
constexpr std::string_view c_notAvailable = "N/A";

// Converts session volume entries into the all-string shape used for "volume list --format json".
VolumeOutputInformation ToVolumeOutput(const wslc_schema::VolumeListEntry& volume)
{
VolumeOutputInformation entry;
entry.Availability = c_notAvailable;
entry.Driver = volume.Driver;
entry.Group = c_notAvailable;
entry.Links = c_notAvailable;
entry.Mountpoint = volume.Mountpoint;
entry.Name = volume.Name;
entry.Scope = volume.Scope;
entry.Size = c_notAvailable;
entry.Status = c_notAvailable;

for (const auto& [key, value] : volume.Labels)
{
if (!entry.Labels.empty())
{
entry.Labels += ",";
}

entry.Labels += std::format("{}={}", key, value);
}

return entry;
}

} // namespace

static bool TryInspectVolume(Terminal& terminal, Session& session, const std::string& volumeName, std::optional<wslc_schema::InspectVolume>& inspectData)
{
try
Expand Down Expand Up @@ -177,7 +212,7 @@ void ListVolumes(CLIExecutionContext& context)
{
for (const auto& volume : volumes)
{
context.Terminal.Output(L"{}\n", ToJsonW(volume, c_jsonCompactIndent));
context.Terminal.Output(L"{}\n", ToJsonW(ToVolumeOutput(volume), c_jsonCompactIndent));
}

break;
Expand Down
3 changes: 3 additions & 0 deletions src/windows/wslcsession/IWSLCVolume.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class IWSLCVolume
// The user-specified labels on this volume (excludes the WSLC metadata label).
virtual const std::map<std::string, std::string>& Labels() const noexcept = 0;

// The path at which the volume is mounted inside the utility VM.
virtual const std::string& Mountpoint() const noexcept = 0;

// The status of the volume as {Code, Message}: S_OK with an empty message when the volume
// opened successfully and is usable, otherwise a failure HRESULT and a human-readable reason
// (e.g. the backing VHD is missing).
Expand Down
4 changes: 4 additions & 0 deletions src/windows/wslcsession/WSLCGuestVolume.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class WSLCGuestVolumeImpl : public IWSLCVolume
{
return m_labels;
}
const std::string& Mountpoint() const noexcept override
{
return m_mountpoint;
}

void Delete() override;
std::string Inspect() const override;
Expand Down
19 changes: 5 additions & 14 deletions src/windows/wslcsession/WSLCSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2776,16 +2776,14 @@ try
}
CATCH_RETURN();

HRESULT WSLCSession::ListVolumes(const WSLCFilter* Filters, ULONG FiltersCount, WSLCVolumeInformation** Volumes, ULONG* Count)
HRESULT WSLCSession::ListVolumes(const WSLCFilter* Filters, ULONG FiltersCount, LPSTR* Output)
try
{
WSLCExecutionContext context(this);

RETURN_HR_IF_NULL(E_POINTER, Volumes);
RETURN_HR_IF_NULL(E_POINTER, Count);
RETURN_HR_IF_NULL(E_POINTER, Output);

*Volumes = nullptr;
*Count = 0;
*Output = nullptr;

auto filters = wsl::windows::common::wslutil::ParseKeyMultiValuePairs(Filters, FiltersCount);

Expand All @@ -2794,16 +2792,9 @@ try

auto volumeList = m_runtime.Volumes().ListVolumes(std::move(filters));

if (volumeList.empty())
{
return S_OK;
}

auto output = wil::make_unique_cotaskmem<WSLCVolumeInformation[]>(volumeList.size());
memcpy(output.get(), volumeList.data(), volumeList.size() * sizeof(WSLCVolumeInformation));
std::string json = wsl::shared::ToJson(volumeList);
*Output = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(json.c_str()).release();

*Count = static_cast<ULONG>(volumeList.size());
*Volumes = output.release();
return S_OK;
}
CATCH_RETURN();
Expand Down
3 changes: 1 addition & 2 deletions src/windows/wslcsession/WSLCSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,7 @@ class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession
IFACEMETHOD(CreateVolume)(_In_ const WSLCVolumeOptions* Options, _Out_ WSLCVolumeInformation* VolumeInfo) override;
IFACEMETHOD(DeleteVolume)(_In_ LPCSTR Name) override;
IFACEMETHOD(ListVolumes)
(_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ WSLCVolumeInformation** Volumes, _Out_ ULONG* Count)
override;
(_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ LPSTR* Output) override;
IFACEMETHOD(InspectVolume)(_In_ LPCSTR Name, _Out_ LPSTR* Output) override;
IFACEMETHOD(PruneVolumes)
(_In_reads_opt_(FiltersCount) const WSLCFilter* Filters,
Expand Down
4 changes: 4 additions & 0 deletions src/windows/wslcsession/WSLCVhdVolume.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class WSLCVhdVolumeImpl : public IWSLCVolume
{
return m_labels;
}
const std::string& Mountpoint() const noexcept override
{
return m_mountpoint;
}

std::pair<HRESULT, std::string> Status() const override
{
Expand Down
13 changes: 10 additions & 3 deletions src/windows/wslcsession/WSLCVolumes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void WSLCVolumes::DeleteVolume(LPCSTR Name)
m_expectedEvents.emplace_back(Name, VolumeEvent::Destroy);
}

std::vector<WSLCVolumeInformation> WSLCVolumes::ListVolumes(std::map<std::string, std::vector<std::string>>&& Filters) const
std::vector<wsl::windows::common::wslc_schema::VolumeListEntry> WSLCVolumes::ListVolumes(std::map<std::string, std::vector<std::string>>&& Filters) const
{
// Pull the driver filter out and forward everything else to docker for filtering.
// Driver filter is special-cased because our driver concept doesn't map 1:1 to docker's.
Expand Down Expand Up @@ -169,7 +169,7 @@ std::vector<WSLCVolumeInformation> WSLCVolumes::ListVolumes(std::map<std::string

auto lock = m_lock.lock_shared();

std::vector<WSLCVolumeInformation> result;
std::vector<wsl::windows::common::wslc_schema::VolumeListEntry> result;
result.reserve(dockerVolumeNames.size());

for (const auto& [name, vol] : m_volumes)
Expand All @@ -186,7 +186,14 @@ std::vector<WSLCVolumeInformation> WSLCVolumes::ListVolumes(std::map<std::string
continue;
}

result.push_back(vol->GetVolumeInformation());
wsl::windows::common::wslc_schema::VolumeListEntry entry;
entry.Name = vol->Name();
entry.Driver = vol->Driver();
entry.Mountpoint = vol->Mountpoint();
entry.Scope = WSLCVolumeScope;
entry.Labels = vol->Labels();

result.push_back(std::move(entry));
}

return result;
Expand Down
3 changes: 2 additions & 1 deletion src/windows/wslcsession/WSLCVolumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Module Name:
#include "WSLCVolumeMetadata.h"
#include "DockerHTTPClient.h"
#include "DockerEventTracker.h"
#include <wslc_schema.h>

namespace wsl::windows::service::wslc {

Expand All @@ -40,7 +41,7 @@ class WSLCVolumes

void DeleteVolume(_In_ LPCSTR Name);

std::vector<WSLCVolumeInformation> ListVolumes(std::map<std::string, std::vector<std::string>>&& Filters) const;
std::vector<wsl::windows::common::wslc_schema::VolumeListEntry> ListVolumes(std::map<std::string, std::vector<std::string>>&& Filters) const;

struct PruneVolumesResult
{
Expand Down
Loading