master
cpp 154 lines 4.79 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCGuestVolume.cpp
8
9 Abstract:
10
11 Implementation of WSLCGuestVolumeImpl - a WSLC volume whose storage is
12 owned entirely by docker's built-in "local" driver inside the guest VM.
13
14 --*/
15
16 #include "precomp.h"
17 #include "DockerHTTPClient.h"
18 #include "WSLCGuestVolume.h"
19 #include "WSLCVolumeMetadata.h"
20 #include "wslc_schema.h"
21
22 using namespace wsl::windows::common;
23 using wsl::shared::Localization;
24
25 namespace wsl::windows::service::wslc {
26
27 namespace {
28
29 // The Docker local driver passes type/device/o directly to mount(8).
30 // Validate that the driver opts are either empty or only contain "type=tmpfs".
31 void ValidateDriverOpts(const std::map<std::string, std::string>& DriverOpts)
32 {
33 if (DriverOpts.empty())
34 {
35 return;
36 }
37
38 // Determine the mount type. Only tmpfs is supported; everything else
39 // (none, nfs, cifs, ext4, ...) requires a device path or network access.
40 auto typeIt = DriverOpts.find("type");
41 std::string type = (typeIt != DriverOpts.end()) ? typeIt->second : "";
42
43 THROW_HR_WITH_USER_ERROR_IF(
44 E_INVALIDARG, Localization::MessageWslcUnsupportedVolumeDriverOpts("type=" + type), !type.empty() && type != "tmpfs");
45 }
46
47 } // namespace
48
49 WSLCGuestVolumeImpl::WSLCGuestVolumeImpl(
50 std::string&& Name,
51 std::string&& CreatedAt,
52 std::string&& Mountpoint,
53 std::map<std::string, std::string>&& DriverOpts,
54 std::map<std::string, std::string>&& Labels,
55 DockerHTTPClient& DockerClient) :
56 m_name(std::move(Name)),
57 m_createdAt(std::move(CreatedAt)),
58 m_mountpoint(std::move(Mountpoint)),
59 m_driverOpts(std::move(DriverOpts)),
60 m_labels(std::move(Labels)),
61 m_dockerClient(DockerClient)
62 {
63 }
64
65 std::unique_ptr<WSLCGuestVolumeImpl> WSLCGuestVolumeImpl::Create(
66 LPCSTR Name, std::map<std::string, std::string>&& DriverOpts, std::map<std::string, std::string>&& Labels, DockerHTTPClient& DockerClient)
67 {
68 ValidateDriverOpts(DriverOpts);
69
70 docker_schema::CreateVolume request{};
71 if (Name != nullptr && Name[0] != '\0')
72 {
73 request.Name = Name;
74 }
75 request.Driver = "local";
76 request.DriverOpts = DriverOpts;
77
78 // Merge user labels into the Docker volume labels.
79 for (const auto& [key, value] : Labels)
80 {
81 request.Labels[key] = value;
82 }
83
84 try
85 {
86 auto createdVolume = DockerClient.CreateVolume(request);
87
88 return std::make_unique<WSLCGuestVolumeImpl>(
89 std::move(createdVolume.Name),
90 std::move(createdVolume.CreatedAt),
91 std::move(createdVolume.Mountpoint),
92 std::move(DriverOpts),
93 std::move(Labels),
94 DockerClient);
95 }
96 CATCH_AND_THROW_DOCKER_USER_ERROR("Failed to create volume '%hs'", Name != nullptr ? Name : "");
97 }
98
99 std::unique_ptr<WSLCGuestVolumeImpl> WSLCGuestVolumeImpl::Open(const wsl::windows::common::docker_schema::Volume& Volume, DockerHTTPClient& DockerClient)
100 {
101 THROW_HR_IF(E_INVALIDARG, Volume.Driver != "local");
102
103 if (Volume.Options.has_value())
104 {
105 ValidateDriverOpts(Volume.Options.value());
106 }
107
108 std::map<std::string, std::string> driverOpts = Volume.Options.value_or(std::map<std::string, std::string>{});
109 std::map<std::string, std::string> labels = Volume.Labels.value_or(std::map<std::string, std::string>{});
110
111 return std::make_unique<WSLCGuestVolumeImpl>(
112 std::string{Volume.Name}, std::string{Volume.CreatedAt}, std::string{Volume.Mountpoint}, std::move(driverOpts), std::move(labels), DockerClient);
113 }
114
115 void WSLCGuestVolumeImpl::Delete()
116 {
117 try
118 {
119 m_dockerClient.RemoveVolume(m_name);
120 }
121 catch (const DockerHTTPException& e)
122 {
123 THROW_HR_WITH_USER_ERROR_IF(
124 HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), Localization::MessageWslcVolumeInUse(m_name.c_str()), e.StatusCode() == 409);
125 THROW_HR_WITH_USER_ERROR_IF(WSLC_E_VOLUME_NOT_FOUND, Localization::MessageWslcVolumeNotFound(m_name.c_str()), e.StatusCode() == 404);
126 THROW_DOCKER_USER_ERROR_MSG(e, "Failed to delete volume '%hs'", m_name.c_str());
127 }
128 }
129
130 std::string WSLCGuestVolumeImpl::Inspect() const
131 {
132 wslc_schema::InspectVolume inspect{};
133 inspect.Name = m_name;
134 inspect.Driver = WSLCGuestVolumeDriver;
135 inspect.CreatedAt = m_createdAt;
136 inspect.Mountpoint = m_mountpoint;
137 inspect.Scope = WSLCVolumeScope;
138 inspect.Options = m_driverOpts;
139 inspect.Labels = m_labels;
140
141 return wsl::shared::ToJson(inspect);
142 }
143
144 WSLCVolumeInformation WSLCGuestVolumeImpl::GetVolumeInformation() const
145 {
146 WSLCVolumeInformation Info{};
147
148 THROW_HR_IF(E_UNEXPECTED, strcpy_s(Info.Name, m_name.c_str()) != 0);
149 THROW_HR_IF(E_UNEXPECTED, strcpy_s(Info.Driver, WSLCGuestVolumeDriver) != 0);
150
151 return Info;
152 }
153
154 } // namespace wsl::windows::service::wslc