diff --git a/internal/hcsoci/hcsdoc_wcow.go b/internal/hcsoci/hcsdoc_wcow.go index 5e8f3f8e8e..558acbd2a6 100644 --- a/internal/hcsoci/hcsdoc_wcow.go +++ b/internal/hcsoci/hcsdoc_wcow.go @@ -31,6 +31,8 @@ import ( "github.com/Microsoft/hcsshim/pkg/annotations" ) +const createContainerSubdirectoryForProcessDumpSuffix = "{container_id}" + // A simple wrapper struct around the container mount configs that should be added to the // container. type mountsConfig struct { @@ -416,10 +418,26 @@ func createWindowsContainerDocument(ctx context.Context, coi *createOptionsInter } if dumpPath != "" { + // If dumpPath specified has createContainerSubdirectoryForProcessDumpSuffix substring + // specified as a suffix, then create subdirectory for this container at the specified + // dumpPath location. When a fileshare from the host is mounted to the specified dumpPath, + // this behavior will help identify dumps coming from differnet containers in the pod. + // Check for createContainerSubdirectoryForProcessDumpSuffix in lower case and upper case + if strings.HasSuffix(dumpPath, createContainerSubdirectoryForProcessDumpSuffix) { + // replace {container_id} with the actual container id + dumpPath = strings.TrimSuffix(dumpPath, createContainerSubdirectoryForProcessDumpSuffix) + coi.ID + } else if strings.HasSuffix(dumpPath, strings.ToUpper(createContainerSubdirectoryForProcessDumpSuffix)) { + // replace {CONTAINER_ID} with the actual container id + dumpPath = strings.TrimSuffix(dumpPath, strings.ToUpper(createContainerSubdirectoryForProcessDumpSuffix)) + coi.ID + } dumpType, err := parseDumpType(coi.Spec.Annotations) if err != nil { return nil, nil, err } + dumpCount, err := parseDumpCount(coi.Spec.Annotations) + if err != nil { + return nil, nil, err + } // Setup WER registry keys for local process dump creation if specified. // https://docs.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps @@ -442,6 +460,15 @@ func createWindowsContainerDocument(ctx context.Context, coi *createOptionsInter DWordValue: dumpType, Type_: "DWord", }, + { + Key: &hcsschema.RegistryKey{ + Hive: "Software", + Name: "Microsoft\\Windows\\Windows Error Reporting\\LocalDumps", + }, + Name: "DumpCount", + DWordValue: dumpCount, + Type_: "DWord", + }, }...) } @@ -479,6 +506,23 @@ func parseAssignedDevices(ctx context.Context, coi *createOptionsInternal, v2 *h return nil } +func parseDumpCount(annots map[string]string) (int32, error) { + dmpCountStr := annots[annotations.WCOWProcessDumpCount] + if dmpCountStr == "" { + // If no count is specified, default of 10 is set. + return 10, nil + } + + dumpCount, err := strconv.Atoi(dmpCountStr) + if err != nil { + return -1, err + } + if dumpCount > 0 { + return int32(dumpCount), nil + } + return -1, fmt.Errorf("invaid dump count specified: %v", dmpCountStr) +} + // parseDumpType parses the passed in string representation of the local user mode process dump type to the // corresponding value the registry expects to be set. // diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go index 4b89e047d9..76c92e1209 100644 --- a/pkg/annotations/annotations.go +++ b/pkg/annotations/annotations.go @@ -233,6 +233,11 @@ const ( // See DumpType: https://docs.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps WCOWProcessDumpType = "io.microsoft.wcow.processdumptype" + // WCOWProcessDumpCount specifies the maximum number of dumps to be collected in the specified + // ContainerProcessDumpLocation path. When the maximum value is exceeded, the oldest dump file in the + // folder will be replaced by the new dump file. The default value is 10. + WCOWProcessDumpCount = "io.microsoft.wcow.processdumpcount" + // RLimitCore specifies the core rlimit value for a container. This will need to be set // in order to have core dumps generated for a given container. RLimitCore = "io.microsoft.lcow.rlimitcore"