Skip to content

Commit 993f565

Browse files
authored
Merge pull request #2524 from marma-dev/main
Adding support for WCOW UVM log forward service
2 parents ae8f7ce + 7e76d92 commit 993f565

File tree

18 files changed

+399
-38
lines changed

18 files changed

+399
-38
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ require (
3939
go.etcd.io/bbolt v1.4.0
4040
go.opencensus.io v0.24.0
4141
go.uber.org/mock v0.6.0
42+
golang.org/x/net v0.43.0
4243
golang.org/x/sync v0.16.0
4344
golang.org/x/sys v0.35.0
4445
google.golang.org/grpc v1.75.0
@@ -113,7 +114,6 @@ require (
113114
go.opentelemetry.io/otel/trace v1.37.0 // indirect
114115
golang.org/x/crypto v0.41.0 // indirect
115116
golang.org/x/mod v0.27.0 // indirect
116-
golang.org/x/net v0.43.0 // indirect
117117
golang.org/x/text v0.28.0 // indirect
118118
golang.org/x/tools v0.36.0 // indirect
119119
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect

internal/gcs/bridge.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ func (brdg *bridge) recvLoop() error {
332332
}
333333

334334
case prot.MsgTypeNotify:
335-
if typ != prot.NotifyContainer|prot.MsgTypeNotify {
335+
if typ != prot.NotifyContainer|prot.ComputeSystem|prot.MsgTypeNotify {
336336
return fmt.Errorf("bridge received unknown unknown notification message %s", typ)
337337
}
338338
var ntf prot.ContainerNotification

internal/gcs/bridge_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func notifyThroughBridge(t *testing.T, typ prot.MsgType, msg interface{}, fn not
179179
func TestBridgeNotify(t *testing.T) {
180180
ntf := &prot.ContainerNotification{Operation: "testing"}
181181
recvd := false
182-
err := notifyThroughBridge(t, prot.MsgTypeNotify|prot.NotifyContainer, ntf, func(nntf *prot.ContainerNotification) error {
182+
err := notifyThroughBridge(t, prot.MsgTypeNotify|prot.ComputeSystem|prot.NotifyContainer, ntf, func(nntf *prot.ContainerNotification) error {
183183
if !reflect.DeepEqual(ntf, nntf) {
184184
t.Errorf("%+v != %+v", ntf, nntf)
185185
}
@@ -197,7 +197,7 @@ func TestBridgeNotify(t *testing.T) {
197197
func TestBridgeNotifyFailure(t *testing.T) {
198198
ntf := &prot.ContainerNotification{Operation: "testing"}
199199
errMsg := "notify should have failed"
200-
err := notifyThroughBridge(t, prot.MsgTypeNotify|prot.NotifyContainer, ntf, func(nntf *prot.ContainerNotification) error {
200+
err := notifyThroughBridge(t, prot.MsgTypeNotify|prot.ComputeSystem|prot.NotifyContainer, ntf, func(nntf *prot.ContainerNotification) error {
201201
return errors.New(errMsg)
202202
})
203203
if err == nil || !strings.Contains(err.Error(), errMsg) {

internal/gcs/guestcaps.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ func (w *WCOWGuestDefinedCapabilities) IsDumpStacksSupported() bool {
100100
func (w *WCOWGuestDefinedCapabilities) IsDeleteContainerStateSupported() bool {
101101
return w.DeleteContainerStateSupported
102102
}
103+
104+
func (w *WCOWGuestDefinedCapabilities) IsLogForwardingSupported() bool {
105+
return w.LogForwardingSupported
106+
}

internal/gcs/guestconnection.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,20 @@ func (gc *GuestConnection) Modify(ctx context.Context, settings interface{}) (er
184184
return gc.brdg.RPC(ctx, prot.RPCModifySettings, &req, &resp, false)
185185
}
186186

187+
func (gc *GuestConnection) ModifyServiceSettings(ctx context.Context, serviceType prot.ServiceModifyPropertyType, settings interface{}) (err error) {
188+
ctx, span := oc.StartSpan(ctx, "gcs::GuestConnection::ModifyServiceSettings", oc.WithClientSpanKind)
189+
defer span.End()
190+
defer func() { oc.SetSpanStatus(span, err) }()
191+
192+
req := prot.ServiceModificationRequest{
193+
RequestBase: makeRequest(ctx, nullContainerID),
194+
PropertyType: string(serviceType),
195+
Settings: settings,
196+
}
197+
var resp prot.ResponseBase
198+
return gc.brdg.RPC(ctx, prot.RPCModifyServiceSettings, &req, &resp, false)
199+
}
200+
187201
func (gc *GuestConnection) DumpStacks(ctx context.Context) (response string, err error) {
188202
ctx, span := oc.StartSpan(ctx, "gcs::GuestConnection::DumpStacks", oc.WithClientSpanKind)
189203
defer span.End()

internal/gcs/guestconnection_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func simpleGcsLoop(t *testing.T, rw io.ReadWriter) error {
131131
return err
132132
}
133133
time.Sleep(50 * time.Millisecond)
134-
err = sendJSON(t, rw, prot.MsgType(prot.MsgTypeNotify|prot.NotifyContainer), 0, &prot.ContainerNotification{
134+
err = sendJSON(t, rw, prot.MsgType(prot.MsgTypeNotify|prot.ComputeSystem|prot.NotifyContainer), 0, &prot.ContainerNotification{
135135
RequestBase: prot.RequestBase{
136136
ContainerID: req.ContainerID,
137137
},

internal/gcs/prot/protocol.go

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ var WindowsGcsHvHostID = guid.GUID{
7171
Data4: [8]uint8{0x93, 0xfe, 0x42, 0x96, 0x9a, 0xe6, 0xd8, 0xd1},
7272
}
7373

74+
// WindowsLoggingHvsockServiceID is the hvsock service ID that the Windows log forward service
75+
// will connect to. 172dad59-976d-45f2-8b6c-6d1b13f2ac4d
76+
var WindowsLoggingHvsockServiceID = guid.GUID{
77+
Data1: 0x172dad59,
78+
Data2: 0x976d,
79+
Data3: 0x45f2,
80+
Data4: [8]uint8{0x8b, 0x6c, 0x6d, 0x1b, 0x13, 0xf2, 0xac, 0x4d},
81+
}
82+
7483
type AnyInString struct {
7584
Value interface{}
7685
}
@@ -83,10 +92,17 @@ func (a *AnyInString) UnmarshalText(b []byte) error {
8392
return json.Unmarshal(b, &a.Value)
8493
}
8594

95+
const (
96+
// Message_Category for the GCS protocol.
97+
ComputeSystem = 0x00100000
98+
ComputeService = 0x00200000
99+
)
100+
86101
type RPCProc uint32
87102

88103
const (
89-
RPCCreate RPCProc = (iota+1)<<8 | 1
104+
// Compute System RPCs
105+
RPCCreate RPCProc = ComputeSystem | (iota+1)<<8 | 1
90106
RPCStart
91107
RPCShutdownGraceful
92108
RPCShutdownForced
@@ -103,6 +119,17 @@ const (
103119
RPCLifecycleNotification
104120
)
105121

122+
const (
123+
// Compute Service RPCs
124+
RPCModifyServiceSettings RPCProc = ComputeService | (iota+1)<<8 | 1
125+
)
126+
127+
type ServiceModifyPropertyType string
128+
129+
const (
130+
LogForwardService = ServiceModifyPropertyType("LogForwardService")
131+
)
132+
106133
func (rpc RPCProc) String() string {
107134
switch rpc {
108135
case RPCCreate:
@@ -135,6 +162,8 @@ func (rpc RPCProc) String() string {
135162
return "UpdateContainer"
136163
case RPCLifecycleNotification:
137164
return "LifecycleNotification"
165+
case RPCModifyServiceSettings:
166+
return "ModifyServiceSettings"
138167
default:
139168
return "0x" + strconv.FormatUint(uint64(rpc), 16)
140169
}
@@ -143,10 +172,10 @@ func (rpc RPCProc) String() string {
143172
type MsgType uint32
144173

145174
const (
146-
MsgTypeRequest MsgType = 0x10100000
147-
MsgTypeResponse MsgType = 0x20100000
148-
MsgTypeNotify MsgType = 0x30100000
149-
MsgTypeMask MsgType = 0xfff00000
175+
MsgTypeRequest MsgType = 0x10000000
176+
MsgTypeResponse MsgType = 0x20000000
177+
MsgTypeNotify MsgType = 0x30000000
178+
MsgTypeMask MsgType = 0xf0000000
150179

151180
NotifyContainer = 1<<8 | 1
152181
)
@@ -160,7 +189,7 @@ func (typ MsgType) String() string {
160189
s = "Response("
161190
case MsgTypeNotify:
162191
s = "Notify("
163-
switch typ - MsgTypeNotify {
192+
switch typ - (ComputeSystem | MsgTypeNotify) {
164193
case NotifyContainer:
165194
s += "Container"
166195
default:
@@ -267,6 +296,12 @@ type ContainerNotification struct {
267296
ResultInfo AnyInString `json:",omitempty"`
268297
}
269298

299+
type ServiceModificationRequest struct {
300+
RequestBase
301+
PropertyType string // ServiceModifyPropertyType
302+
Settings interface{} `json:",omitempty"`
303+
}
304+
270305
type ContainerExecuteProcess struct {
271306
RequestBase
272307
Settings ExecuteProcessSettings
@@ -345,13 +380,14 @@ type ContainerModifySettings struct {
345380
}
346381

347382
type GcsCapabilities struct {
348-
SendHostCreateMessage bool
349-
SendHostStartMessage bool
350-
HvSocketConfigOnStartup bool
351-
SendLifecycleNotifications bool
352-
SupportedSchemaVersions []hcsschema.Version
353-
RuntimeOsType string
354-
GuestDefinedCapabilities json.RawMessage
383+
SendHostCreateMessage bool
384+
SendHostStartMessage bool
385+
HvSocketConfigOnStartup bool
386+
SendLifecycleNotifications bool
387+
ModifyServiceSettingsSupported bool
388+
SupportedSchemaVersions []hcsschema.Version
389+
RuntimeOsType string
390+
GuestDefinedCapabilities json.RawMessage
355391
}
356392

357393
type ContainerCreateResponse struct {

internal/hcs/schema1/schema1.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ type GuestDefinedCapabilities struct {
221221
DumpStacksSupported bool `json:",omitempty"`
222222
DeleteContainerStateSupported bool `json:",omitempty"`
223223
UpdateContainerSupported bool `json:",omitempty"`
224+
LogForwardingSupported bool `json:",omitempty"`
224225
}
225226

226227
// GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM

internal/oci/uvm.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,12 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) (
418418
if err := handleWCOWSecurityPolicy(ctx, s.Annotations, wopts); err != nil {
419419
return nil, err
420420
}
421-
421+
// If security policy is enable, wopts.ForwardLogs default value should be false
422+
if wopts.SecurityPolicyEnabled {
423+
wopts.ForwardLogs = false
424+
}
425+
wopts.LogSources = ParseAnnotationsString(s.Annotations, annotations.LogSources, wopts.LogSources)
426+
wopts.ForwardLogs = ParseAnnotationsBool(ctx, s.Annotations, annotations.ForwardLogs, wopts.ForwardLogs)
422427
return wopts, nil
423428
}
424429
return nil, errors.New("cannot create UVM opts spec is not LCOW or WCOW")

internal/oci/uvm_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ func Test_SpecToUVMCreateOptions_Default_WCOW(t *testing.T) {
117117
wopts := (opts).(*uvm.OptionsWCOW)
118118
dopts := uvm.NewDefaultOptionsWCOW(t.Name(), "")
119119

120+
// output handler equality is always false, so set to nil
121+
wopts.OutputHandlerCreator = nil
122+
dopts.OutputHandlerCreator = nil
123+
120124
if !cmp.Equal(*wopts, *dopts) {
121125
t.Fatalf("should not have updated create options from default when no annotation are provided:\n%s", cmp.Diff(wopts, dopts))
122126
}

0 commit comments

Comments
 (0)