1
2
3
4 package hcsoci
5
6
7
8 import (
9 "bytes"
10 "context"
11 "fmt"
12 "os"
13 "path/filepath"
14 "strings"
15
16 specs "github.com/opencontainers/runtime-spec/specs-go"
17 "github.com/pkg/errors"
18
19 "github.com/Microsoft/hcsshim/internal/cmd"
20 "github.com/Microsoft/hcsshim/internal/credentials"
21 "github.com/Microsoft/hcsshim/internal/guestpath"
22 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
23 "github.com/Microsoft/hcsshim/internal/layers"
24 "github.com/Microsoft/hcsshim/internal/log"
25 "github.com/Microsoft/hcsshim/internal/resources"
26 "github.com/Microsoft/hcsshim/internal/schemaversion"
27 "github.com/Microsoft/hcsshim/internal/uvm"
28 "github.com/Microsoft/hcsshim/internal/wclayer"
29 )
30
31 const wcowSandboxMountPath = "C:\\SandboxMounts"
32
33 func allocateWindowsResources(ctx context.Context, coi *createOptionsInternal, r *resources.Resources, isSandbox bool) error {
34 if coi.Spec == nil || coi.Spec.Windows == nil || coi.Spec.Windows.LayerFolders == nil {
35 return errors.New("field 'Spec.Windows.Layerfolders' is not populated")
36 }
37
38 scratchFolder := coi.Spec.Windows.LayerFolders[len(coi.Spec.Windows.LayerFolders)-1]
39
40
41
42 if _, err := os.Stat(scratchFolder); os.IsNotExist(err) {
43 if err := os.MkdirAll(scratchFolder, 0777); err != nil {
44 return errors.Wrapf(err, "failed to auto-create container scratch folder %s", scratchFolder)
45 }
46 }
47
48
49
50 if _, err := os.Stat(filepath.Join(scratchFolder, "sandbox.vhdx")); os.IsNotExist(err) {
51 if err := wclayer.CreateScratchLayer(ctx, scratchFolder, coi.Spec.Windows.LayerFolders[:len(coi.Spec.Windows.LayerFolders)-1]); err != nil {
52 return errors.Wrap(err, "failed to CreateSandboxLayer")
53 }
54 }
55
56 if coi.Spec.Root == nil {
57 coi.Spec.Root = &specs.Root{}
58 }
59
60 if coi.Spec.Root.Path == "" && (coi.HostingSystem != nil || coi.Spec.Windows.HyperV == nil) {
61 log.G(ctx).Debug("hcsshim::allocateWindowsResources mounting storage")
62 containerRootInUVM := r.ContainerRootInUVM()
63 containerRootPath, closer, err := layers.MountWCOWLayers(ctx, coi.actualID, coi.Spec.Windows.LayerFolders, containerRootInUVM, "", coi.HostingSystem)
64 if err != nil {
65 return errors.Wrap(err, "failed to mount container storage")
66 }
67 coi.Spec.Root.Path = containerRootPath
68
69
70 if !isSandbox || coi.HostingSystem == nil {
71 r.SetLayers(closer)
72 }
73 }
74
75 if err := setupMounts(ctx, coi, r); err != nil {
76 return err
77 }
78
79 if cs, ok := coi.Spec.Windows.CredentialSpec.(string); ok {
80
81 if schemaversion.IsV21(coi.actualSchemaVersion) {
82 hypervisorIsolated := coi.HostingSystem != nil
83 ccgInstance, ccgResource, err := credentials.CreateCredentialGuard(ctx, coi.actualID, cs, hypervisorIsolated)
84 if err != nil {
85 return err
86 }
87 coi.ccgState = ccgInstance.CredentialGuard
88 r.Add(ccgResource)
89 if hypervisorIsolated {
90
91
92
93
94
95
96
97
98
99 hvSockConfig := ccgInstance.HvSocketConfig
100 if err := coi.HostingSystem.UpdateHvSocketService(ctx, hvSockConfig.ServiceId, hvSockConfig.ServiceConfig); err != nil {
101 return errors.Wrap(err, "failed to update hvsocket service")
102 }
103 }
104 }
105 }
106
107 if coi.HostingSystem != nil {
108 if coi.hasWindowsAssignedDevices() {
109 windowsDevices, closers, err := handleAssignedDevicesWindows(ctx, coi.HostingSystem, coi.Spec.Annotations, coi.Spec.Windows.Devices)
110 if err != nil {
111 return err
112 }
113 r.Add(closers...)
114 coi.Spec.Windows.Devices = windowsDevices
115 }
116
117
118
119 driverClosers, err := addSpecGuestDrivers(ctx, coi.HostingSystem, coi.Spec.Annotations)
120 if err != nil {
121 return err
122 }
123 r.Add(driverClosers...)
124 }
125
126 return nil
127 }
128
129
130
131 func setupMounts(ctx context.Context, coi *createOptionsInternal, r *resources.Resources) error {
132
133
134
135 for _, mount := range coi.Spec.Mounts {
136 if mount.Destination == "" || mount.Source == "" {
137 return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
138 }
139 switch mount.Type {
140 case "":
141 case MountTypePhysicalDisk:
142 case MountTypeVirtualDisk:
143 case MountTypeExtensibleVirtualDisk:
144 default:
145 return fmt.Errorf("invalid OCI spec - Type '%s' not supported", mount.Type)
146 }
147
148 if coi.HostingSystem != nil && schemaversion.IsV21(coi.actualSchemaVersion) {
149 uvmPath := fmt.Sprintf(guestpath.WCOWGlobalMountPrefixFmt, coi.HostingSystem.UVMMountCounter())
150 readOnly := false
151 for _, o := range mount.Options {
152 if strings.ToLower(o) == "ro" {
153 readOnly = true
154 break
155 }
156 }
157 l := log.G(ctx).WithField("mount", fmt.Sprintf("%+v", mount))
158 if mount.Type == MountTypePhysicalDisk || mount.Type == MountTypeVirtualDisk || mount.Type == MountTypeExtensibleVirtualDisk {
159 var (
160 scsiMount *uvm.SCSIMount
161 err error
162 )
163 switch mount.Type {
164 case MountTypePhysicalDisk:
165 l.Debug("hcsshim::allocateWindowsResources Hot-adding SCSI physical disk for OCI mount")
166 scsiMount, err = coi.HostingSystem.AddSCSIPhysicalDisk(
167 ctx,
168 mount.Source,
169 uvmPath,
170 readOnly,
171 mount.Options,
172 )
173 case MountTypeVirtualDisk:
174 l.Debug("hcsshim::allocateWindowsResources Hot-adding SCSI virtual disk for OCI mount")
175 scsiMount, err = coi.HostingSystem.AddSCSI(
176 ctx,
177 mount.Source,
178 uvmPath,
179 readOnly,
180 false,
181 mount.Options,
182 uvm.VMAccessTypeIndividual,
183 )
184 case MountTypeExtensibleVirtualDisk:
185 l.Debug("hcsshim::allocateWindowsResource Hot-adding ExtensibleVirtualDisk")
186 scsiMount, err = coi.HostingSystem.AddSCSIExtensibleVirtualDisk(
187 ctx,
188 mount.Source,
189 uvmPath,
190 readOnly,
191 )
192 }
193 if err != nil {
194 return fmt.Errorf("adding SCSI mount %+v: %w", mount, err)
195 }
196 r.Add(scsiMount)
197
198
199 coi.windowsAdditionalMounts = append(coi.windowsAdditionalMounts, hcsschema.MappedDirectory{
200 HostPath: scsiMount.UVMPath,
201 ContainerPath: mount.Destination,
202 ReadOnly: readOnly,
203 })
204 } else if strings.HasPrefix(mount.Source, guestpath.SandboxMountPrefix) {
205
206
207
208
209
210 sandboxPath := convertToWCOWSandboxMountPath(mount.Source)
211
212
213
214
215
216
217 b := &bytes.Buffer{}
218 stderr, err := cmd.CreatePipeAndListen(b, false)
219 if err != nil {
220 return err
221 }
222 req := &cmd.CmdProcessRequest{
223 Args: []string{"cmd", "/c", "mkdir", sandboxPath, "&", "dir", sandboxPath},
224 Stderr: stderr,
225 }
226 exitCode, err := cmd.ExecInUvm(ctx, coi.HostingSystem, req)
227 if err != nil {
228 return errors.Wrapf(err, "failed to create sandbox mount directory in utility VM with exit code %d %q", exitCode, b.String())
229 }
230 } else {
231 if uvm.IsPipe(mount.Source) {
232 pipe, err := coi.HostingSystem.AddPipe(ctx, mount.Source)
233 if err != nil {
234 return errors.Wrap(err, "failed to add named pipe to UVM")
235 }
236 r.Add(pipe)
237 } else {
238 l.Debug("hcsshim::allocateWindowsResources Hot-adding VSMB share for OCI mount")
239 options := coi.HostingSystem.DefaultVSMBOptions(readOnly)
240 share, err := coi.HostingSystem.AddVSMB(ctx, mount.Source, options)
241 if err != nil {
242 return errors.Wrapf(err, "failed to add VSMB share to utility VM for mount %+v", mount)
243 }
244 r.Add(share)
245 }
246 }
247 }
248 }
249
250 return nil
251 }
252
253 func convertToWCOWSandboxMountPath(source string) string {
254 subPath := strings.TrimPrefix(source, guestpath.SandboxMountPrefix)
255 return filepath.Join(wcowSandboxMountPath, subPath)
256 }
257
View as plain text