-
Notifications
You must be signed in to change notification settings - Fork 272
Adding support for WCOW UVM log forward service #2524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@microsoft-github-policy-service agree company="Microsoft" |
a0a0dcd
to
e4214fd
Compare
Signed-off-by: Manish Ranjan Mahanta <mmahanta@microsoft.com>
MsgTypeRequest MsgType = 0x10000000 | ||
MsgTypeResponse MsgType = 0x20000000 | ||
MsgTypeNotify MsgType = 0x30000000 | ||
MsgTypeMask MsgType = 0xf0000000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if uvm.OS() == "windows" && uvm.gc != nil { | ||
wcaps := gcs.GetWCOWCapabilities(uvm.gc.Capabilities()) | ||
if wcaps != nil && wcaps.IsLogForwardingSupported() { | ||
req := guestrequest.LogForwardServiceRPCRequest{ | ||
RPCType: guestrequest.RPCStartLogForwarding, | ||
Settings: "", | ||
} | ||
err := uvm.gc.ModifyServiceSettings(ctx, prot.LogForwardService, req) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
log.G(ctx).WithField("os", uvm.operatingSystem).Error("Log forwarding not supported for this OS") | ||
} | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if uvm.OS() == "windows" && uvm.gc != nil { | |
wcaps := gcs.GetWCOWCapabilities(uvm.gc.Capabilities()) | |
if wcaps != nil && wcaps.IsLogForwardingSupported() { | |
req := guestrequest.LogForwardServiceRPCRequest{ | |
RPCType: guestrequest.RPCStartLogForwarding, | |
Settings: "", | |
} | |
err := uvm.gc.ModifyServiceSettings(ctx, prot.LogForwardService, req) | |
if err != nil { | |
return err | |
} | |
} else { | |
log.G(ctx).WithField("os", uvm.operatingSystem).Error("Log forwarding not supported for this OS") | |
} | |
} | |
return nil | |
if uvm.OS() != "windows" || uvm.gc == nil { | |
return nil | |
} | |
wcaps := gcs.GetWCOWCapabilities(uvm.gc.Capabilities()) | |
if wcaps != nil && wcaps.IsLogForwardingSupported() { | |
req := guestrequest.LogForwardServiceRPCRequest{ | |
RPCType: guestrequest.RPCStartLogForwarding, | |
Settings: "", | |
} | |
err := uvm.gc.ModifyServiceSettings(ctx, prot.LogForwardService, req) | |
if err != nil { | |
return err | |
} | |
} else { | |
log.G(ctx).WithField("os", uvm.operatingSystem).Error("Log forwarding not supported for this OS") | |
} |
type ServiceModifyPropertyType uint32 | ||
|
||
const ( | ||
LogForwardService ServiceModifyPropertyType = iota | ||
) | ||
|
||
func (m ServiceModifyPropertyType) String() string { | ||
switch m { | ||
case LogForwardService: | ||
return "LogForwardService" | ||
default: | ||
return fmt.Sprintf("UnknownModifyServiceType(%d)", m) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not have ServiceModifyPropertyType
be a string, similar to the PropertyType
and RequestType
enums, since we don't ever need to use the integer value?\
type ServiceModifyPropertyType string
const (
LogForwardService = ServiceModifyPropertyType("LogForwardService")
)
// ...
type ServiceModificationRequest struct {
RequestBase
PropertyType ServiceModifyPropertyType `json:",omitempty"`
Settings interface{} `json:",omitempty"`
}
// Original ETW Event Data may have "message" or "Message" field instead of "msg" | ||
|
||
if e.Message == "" && e.Fields["message"] != nil { | ||
e.Message = e.Fields["message"].(string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this (and L78-81) will panic if for some reason the message isn't a string
e.Message = e.Fields["message"].(string) | |
if msg, ok := e.Fields["message"].(string); ok { | |
e.Message = msg | |
} |
// lifecycle. This approach potentially allows to wait for reconnections, | ||
// while limiting the number of concurrent connections to 1. | ||
// This is useful for the case when logging service is restarted. | ||
g.Go(func() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we actually need this line, or can we start the below goroutine immediately (since the function passed to g.Go
simply starts a go routine and returns immediately)
) | ||
|
||
func (uvm *UtilityVM) StartLogForwarding(ctx context.Context) error { | ||
// Implementation for stopping the log forwarder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Implementation for stopping the log forwarder | |
// Implementation for starting the log forwarder |
uvm.outputHandler = opts.OutputHandlerCreator(opts.Options) | ||
uvm.outputProcessingDone = make(chan struct{}) | ||
uvm.outputListener, err = winio.ListenHvsock(&winio.HvsockAddr{ | ||
VMID: uvm.RuntimeID(), | ||
ServiceID: prot.WindowsLoggingHvsockServiceID, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we gate this on uvm.forwardLogs
, so we can skip starting the output handler if we're not forwarding logs
key := prot.WindowsLoggingHvsockServiceID.String() | ||
doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable[key] = hcsschema.HvSocketServiceConfig{ | ||
AllowWildcardBinds: true, | ||
BindSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)", | ||
ConnectSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)", | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar to CreateWCOW
, can we skip this if !uvm.forwardLogs
?
// VSMBNoDirectMap specifies that no direct mapping should be used for any VSMBs added to the UVM. | ||
VSMBNoDirectMap = "io.microsoft.virtualmachine.wcow.virtualSMB.nodirectmap" | ||
|
||
// LogSources specifies the ETW providers to be set for the logging service. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// LogSources specifies the ETW providers to be set for the logging service. | |
// LogSources specifies the ETW providers to be set for the logging service as a base64-encoded JSON string. | |
// | |
// For example: | |
// | |
// { | |
// "logConfig": { | |
// "sources": [ | |
// { | |
// "type": "ETW", | |
// "providers": [ | |
// { | |
// "providerGuid": "80CE50DE-D264-4581-950D-ABADEEE0D340", | |
// "providerName": "Microsoft.Windows.HyperV.Compute", | |
// "level": "Information" | |
// } | |
// ] | |
// } | |
// ] | |
// } | |
// } | |
// | |
// Would be encoded as: | |
// | |
// "io.microsoft.virtualmachine.wcow.logsources" = | |
// "eyJsb2dDb25maWciOnsic291cmNlcyI6W3sidHlwZSI6IkVUVyIsInByb3ZpZGVycyI6W3sicHJvdmlkZXJHdWlkIjoiODBDRTUwREUtRDI2NC00NTgxLTk1MEQtQUJBREVFRTBEMzQwIiwicHJvdmlkZXJOYW1lIjoiTWljcm9zb2Z0LldpbmRvd3MuSHlwZXJWLkNvbXB1dGUiLCJsZXZlbCI6IkluZm9ybWF0aW9uIn1dfV19fQ==" |
LogSources string // ETW providers to be set for the logging service | ||
ForwardLogs bool // Whether to forward logs to the host or not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may want to add a check in "internal\uvm\create.go".verifyOptions
to error if opts.ForwardLogs && opts.LogSources == ""
Adding support to manage control plane operations and receive the log data from the Log Forward Service in the Utility VM.
Control Plane: Based on annotations passed for WCOW pod creation
HcsShim
sends commands via the bridge to the GCS which relays this by calling appropriate RPCs of the Log Forward Service.Data Plane:
HcsShim
creates a HvSocket listener to receive the logs from the Log Forward Service, parses them and re-logs it to the RunHCS ETW providerControl Plane
During protocol negotiation, inbox GCS shall exhibit a new GcsCapabilities called
ModifyServiceSettingsSupported
indicating GCS supports ModifyServiceSettings. Also,GuestDefinedCapabilites
for WCOW shall mentionLogForwardingSupported
indicating Log Forward Service is presentFor Control Plane ops, a new message category
ComputeService
and message typeModifyServiceSettings
is added (following pattern of HCS ModifyServiceSettings). TheSettings
property of theModifyServiceSettings
shall mention the name of service (Log Forward Service for our case), with details of the operation to be called for it (e.g. Modify, Start, Stop). Existing hex interpreting logic to determine type of message had to be modified as they were hardcoded to only expectComputeSystem
category of messages.Annotations for WCOW UVM Create are added
io.microsoft.virtualmachine.wcow.logsources
io.microsoft.virtualmachine.wcow.forwardlogs
By default,
ForwardLogs
would betrue
for WCOW andfalse
for C-WCOW, unless specifiedData Plane
HcsShim creates the HvSocket Listener to listen for connections from the Log Forward Service. This is created irrespectively, as we plan to allow Log Forward Service to connect after UVM creation is done as well, by (later in a different PR) introduce support for enabling the ForwardLogs as part of Update call.
The HvSocket is also created to limit only one concurrent connection at a time, and allow for reconnection (and not close the listener on accept)
On accepting the connection, the output is handled by
ParseLogrus
which has been modified to expect the message to be inmessage
orMessage
which is typical in Windows ETW events