in plugins/cmd/gen-device-mounts/main.go [57:245]
func main() {
// Configure our custom help message
pflag.CommandLine.SetOutput(os.Stderr)
pflag.Usage = func() {
ePrintln("gen-device-mounts: generates flags for exposing devices to containers with `ctr run`")
ePrintln("\nUsage syntax:", os.Args[0], "[-h] [--format text|json] [--all] [--index <INDEX>] [--luid <LUID>] [--path <PATH>] [--run] [--verbose] [<FLAGS TO USE WITH --run>]")
ePrintln("\nOptions:")
pflag.PrintDefaults()
ePrintln(strings.Join([]string{
"",
"The list of available DirectX devices (including their enumeration indices, LUID values, and PCI paths)",
"can be retrieved by running either `test-device-discovery-cpp.exe` or `test-device-discovery-go.exe`.",
"",
"NOTES REGARDING OTHER FRONTENDS",
"-------------------------------",
"",
"Docker:",
"",
"Although Docker version 23.0.0 introduced support for exposing individial devices using their PCI location",
"paths, it still lacks the ability to bind-mount individual files rather than directories, which prevents",
"it from using the flags generated by `gen-device-mounts`. This is due to its continued use of the HCSv1",
"API rather than the newer HCSv2 API used by containerd. When Docker eventually migrates to using HCSv2",
"(or using containerd under Windows the way it does under Linux) then `gen-device-mounts` will be updated",
"to add an option to invoke `docker run` instead of `ctr run` when --run is specified.",
"",
"nerdctl:",
"",
"nerdctl is currently blocked by two outstanding issues that prevent it from using the flags generated by",
"`gen-device-mounts`:",
"",
"- https://github.com/containerd/nerdctl/pull/2079",
"- https://github.com/containerd/nerdctl/issues/759",
"",
"Once these blockers have been resolved then `gen-device-mounts` will be updated to add an option to invoke",
"`nerdctl run` instead of `ctr run` when --run is specified.",
}, "\n"))
os.Exit(1)
}
// Parse our command-line arguments
allDevices := pflag.Bool("all", false, "Expose all available DirectX devices")
outputFormat := pflag.String("format", "text", "The output format for generated flags (\"text\" or \"json\")")
devicesByIndex := pflag.UintSlice("index", []uint{}, "Expose the DirectX device with the specified enumeration index (can be specified multiple times)")
devicesByLUID := pflag.Int64Slice("luid", []int64{}, "Expose the DirectX device with the specified LUID (can be specified multiple times)")
devicesByPath := pflag.StringSlice("path", []string{}, "Expose the DirectX device with the specified PCI path (can be specified multiple times)")
runContainer := pflag.Bool("run", false, "run")
verbose := pflag.Bool("verbose", false, "Enable verbose output")
pflag.Parse()
// Verify that a valid output format was specified
if !contains([]string{"text", "json"}, *outputFormat) {
log.Fatalln("Error: unknown output format \"", *outputFormat, "\" (supported formats are \"text\" and \"json\")")
}
// Print our device selection criteria
if *verbose {
ePrintln("Device selection criteria:")
if *allDevices {
ePrintln("- Include all available DirectX devices")
} else {
if len(*devicesByIndex) > 0 {
ePrintln("- Include DirectX devices with the following enumeration indices:", formatNumbers(*devicesByIndex))
}
if len(*devicesByLUID) > 0 {
ePrintln("- Include DirectX devices with the following LUID values:", formatNumbers(*devicesByLUID))
}
if len(*devicesByPath) > 0 {
ePrintln("- Include DirectX devices with the following PCI paths:", formatStrings(*devicesByPath, ", "))
}
}
ePrintln()
}
// Attempt to load the DirectX device discovery library
if err := discovery.LoadDiscoveryLibrary(); err != nil {
log.Fatalln("Error:", err)
}
// Create a new DeviceDiscovery object
deviceDiscovery, err := discovery.NewDeviceDiscovery()
if err != nil {
log.Fatalln("Error:", err)
}
// Perform device discovery
if err := deviceDiscovery.DiscoverDevices(discovery.AllDevices, true, true); err != nil {
log.Fatalln("Error:", err)
}
// Filter the list of devices based on the specified selection criteria
filtered := []*discovery.Device{}
for index, device := range deviceDiscovery.Devices {
if *allDevices || contains(*devicesByIndex, uint(index)) || contains(*devicesByLUID, device.AdapterLUID) || contains(*devicesByPath, device.LocationPath) {
filtered = append(filtered, device)
}
}
// Print the details of the selected devices
if *verbose {
ePrint("Selected ", len(filtered), " device(s) based on selection criteria:\n")
for index, device := range filtered {
ePrint("- Index ", index, ", LUID ", device.AdapterLUID, ", PCI Path ", device.LocationPath, "\n")
}
ePrintln()
}
// Append our default runtime file mounts to the lists for each device
for _, device := range deviceDiscovery.Devices {
// Determine whether we have any additional runtime files for the device vendor
files, haveFiles := mount.DefaultMounts[strings.ToLower(device.Vendor)]
filesWow64, haveFilesWow64 := mount.DefaultMountsWow64[strings.ToLower(device.Vendor)]
// Merge any additions for System32
if haveFiles {
ignored := device.AppendRuntimeFiles(files)
for _, file := range ignored {
ePrintln("Ignoring additional 64-bit runtime file because it clashes with an existing filename: ", file)
}
}
// Merge any additions for SysWOW64
if haveFilesWow64 {
ignored := device.AppendRuntimeFilesWow64(filesWow64)
for _, file := range ignored {
ePrintln("Ignoring additional 32-bit runtime file because it clashes with an existing filename: ", file)
}
}
}
// Generate the device specs and runtime file mounts for the selected devices
specs := mount.SpecsForDevices(filtered)
mounts := mount.MountsForDevices(filtered)
// Generate the flags for mounting the devices
flags := []string{}
for _, spec := range specs {
flags = append(flags, "--device", spec.HostPath)
}
for _, mount := range mounts {
flags = append(flags, "--mount", fmt.Sprint("src=", mount.HostPath, ",dst=", mount.GetContainerPath()))
}
// Determine whether we are just printing the flags, or running a container with them
if *runContainer {
// Create a command object to represent our `ctr run` invocation
cmd := exec.Command("ctr", "run", "--rm")
// Allow the child process to inherit all standard streams
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
// Append both our generated flags and any loose command-line arguments to the invocation
cmd.Args = append(cmd.Args, flags...)
cmd.Args = append(cmd.Args, pflag.Args()...)
// Print the generated command to stderr, wrapping each flag in quotes
ePrintln(formatStrings(cmd.Args, " "))
// Attempt to run `ctr run`
if err := cmd.Run(); err != nil {
log.Fatalln("Error:", err)
}
} else {
// Determine which format we are using to print the list of flags
if *outputFormat == "json" {
// Attempt to format the flags as a JSON array
formatted, err := json.Marshal(flags)
if err != nil {
log.Fatalln("Error:", err)
}
// Print the JSON array to stdout
fmt.Println(formatted)
} else {
// Print the list of flags to stdout, wrapping each flag in quotes
fmt.Println(formatStrings(flags, " "))
}
}
}