1
2
3 package remotevm
4
5 import (
6 "context"
7 "io"
8 "net"
9 "os/exec"
10
11 "github.com/Microsoft/hcsshim/internal/jobobject"
12 "github.com/Microsoft/hcsshim/internal/log"
13 "github.com/Microsoft/hcsshim/internal/vm"
14 "github.com/Microsoft/hcsshim/internal/vmservice"
15 "github.com/containerd/ttrpc"
16 ptypes "github.com/gogo/protobuf/types"
17 "github.com/pkg/errors"
18 "github.com/sirupsen/logrus"
19 )
20
21 var _ vm.UVMBuilder = &utilityVMBuilder{}
22
23 type utilityVMBuilder struct {
24 id string
25 guestOS vm.GuestOS
26 job *jobobject.JobObject
27 config *vmservice.VMConfig
28 client vmservice.VMService
29 }
30
31 func NewUVMBuilder(ctx context.Context, id, owner, binPath, addr string, guestOS vm.GuestOS) (vm.UVMBuilder, error) {
32 var job *jobobject.JobObject
33 if binPath != "" {
34 log.G(ctx).WithFields(logrus.Fields{
35 "binary": binPath,
36 "address": addr,
37 }).Debug("starting remotevm server process")
38
39 opts := &jobobject.Options{
40 Name: id,
41 }
42 job, err := jobobject.Create(ctx, opts)
43 if err != nil {
44 return nil, errors.Wrap(err, "failed to create job object for remotevm process")
45 }
46
47 cmd := exec.Command(binPath, "--ttrpc", addr)
48 p, err := cmd.StdoutPipe()
49 if err != nil {
50 return nil, errors.Wrap(err, "failed to create stdout pipe")
51 }
52
53 if err := cmd.Start(); err != nil {
54 return nil, errors.Wrap(err, "failed to start remotevm server process")
55 }
56
57 if err := job.Assign(uint32(cmd.Process.Pid)); err != nil {
58 return nil, errors.Wrap(err, "failed to assign remotevm process to job")
59 }
60
61 if err := job.SetTerminateOnLastHandleClose(); err != nil {
62 return nil, errors.Wrap(err, "failed to set terminate on last handle closed for remotevm job object")
63 }
64
65
66 _, _ = io.Copy(io.Discard, p)
67 }
68
69 conn, err := net.Dial("unix", addr)
70 if err != nil {
71 return nil, errors.Wrapf(err, "failed to dial remotevm address %q", addr)
72 }
73
74 c := ttrpc.NewClient(conn, ttrpc.WithOnClose(func() { conn.Close() }))
75 vmClient := vmservice.NewVMClient(c)
76
77 return &utilityVMBuilder{
78 id: id,
79 guestOS: guestOS,
80 config: &vmservice.VMConfig{
81 MemoryConfig: &vmservice.MemoryConfig{},
82 DevicesConfig: &vmservice.DevicesConfig{},
83 ProcessorConfig: &vmservice.ProcessorConfig{},
84 SerialConfig: &vmservice.SerialConfig{},
85 ExtraData: make(map[string]string),
86 },
87 job: job,
88 client: vmClient,
89 }, nil
90 }
91
92 func (uvmb *utilityVMBuilder) Create(ctx context.Context) (vm.UVM, error) {
93
94 capabilities, err := uvmb.client.CapabilitiesVM(ctx, &ptypes.Empty{})
95 if err != nil {
96 return nil, errors.Wrap(err, "failed to get virtstack capabilities from vmservice")
97 }
98
99 if _, err := uvmb.client.CreateVM(ctx, &vmservice.CreateVMRequest{Config: uvmb.config, LogID: uvmb.id}); err != nil {
100 return nil, errors.Wrap(err, "failed to create remote VM")
101 }
102
103 return &utilityVM{
104 id: uvmb.id,
105 job: uvmb.job,
106 config: uvmb.config,
107 client: uvmb.client,
108 capabilities: capabilities,
109 }, nil
110 }
111
View as plain text