Passing Optical Drive to Rockon

I’m trying to create a custom Rockon for a MakeMKV image. I used the existing Handbrake json file as a template. One of the requirements, obviously, is an optical drive to read from. However, when I install the image (successfully), the docker log file shows the following:

[cont-init   ] 54-check-optical-drive.sh: executing...
[cont-init   ] 54-check-optical-drive.sh: looking for usable optical drives...
[cont-init   ] 54-check-optical-drive.sh: found optical drive [/dev/sr0, /dev/sg3], but it is not usable because:
[cont-init   ] 54-check-optical-drive.sh:   --> the host device /dev/sg3 is not exposed to the container.
[cont-init   ] 54-check-optical-drive.sh: no usable optical drive found.
[cont-init   ] 54-check-optical-drive.sh: terminated successfully.

I’m not really sure why that is. The /dev/sg3 requirement doesn’t appear in the original Handbrake file, though I never confirmed whether the optical drive is even accessible there. I can confirm that on my system, /dev/sr0 is definitely the optical drive. Why would both be needed for a single optical drive? And how do I incorporate that as part of the json file? Do I just add a 2nd device section where /dev/sg3 gets added?

Here’s the json file I’ve come up with so far:

{
    "MakeMKV": {
        "containers": {
            "makemkv": {
                "image": "jlesage/makemkv",
                "launch_order": 1,
                "devices": {
                    "opticaldrive": {
                        "description": "Optional: path to optical drive device (e.g., DVD drive at /dev/sr0).Optical drives usually have /dev/srX as device. E.g., the first drive is /dev/sr0, the second /dev/sr1, etc. Leave blank if >
                        "label": "Optical Drive"
                    }
                },
                "ports": {
                    "5800": {
                        "description": "WebUI port defualt 5810",
                        "host_default": 5810,
                        "label": "WebUI port",
                        "protocol": "tcp",
                        "ui": true
                    }
                },
                "volumes": {
                    "/config": {
                        "description": "Choose a Share for configuration.",
                        "label": "Config"
                    },
                    "/storage": {
                        "description": "Choose a Share for Storage",
                        "label": "Data Storage"
                    },
                    "/output": {
                        "description": "Choose a Share for Output",
                        "label": "Output"
                    }
                },
                "environment": {
                    "USER_ID": {
                        "description": "Enter a valid UID to run MakeMKV as. It must have full permissions to all Shares mapped in the previous step.",
                        "label": "UID to run MakeMKV as.",
                        "index": 1
                    },
                    "GROUP_ID": {
                        "description": "Enter a valid GID to use along with the above UID. It (or the above UID) must have full permissions to all Shares mapped in the previous step.",
                        "label": "GID to run MakeMKV as.",
                        "index": 2
                    },
                    "AUTO_DISC_RIPPER": {
                        "description": "When set to 1, the automatic disc ripper is enabled.",
                        "label": "AUTO DISC RIPPER",
                        "index": 3
                    },
                    "AUTO_DISC_RIPPER_EJECT": {
                        "description": "When set to 1, disc is ejected from the drive when ripping is terminated.",
                        "label": "AUTO EJECT",
                        "index": 4
                    },
                    "MAKEMKV_KEY":{
                        "description": "Makekmv key. Set to beta or own bought key",
                        "label": "MakeMKV key",
                        "index": 5
                    }
                }
            }
        },
        "description": "Rip DVD and Blu-ray",
        "ui": {
            "slug": ""
        },
        "volume_add_support": true,
        "website": "https://hub.docker.com/r/jlesage/makemkv/",
        "version": "1.0"
    }
}

Did you add only /dev/sr0 during the setup, and it shows /dev/sg3 as an additionally found device? And then complains it cannot use any of them?

I only have a single optical drive connected, and it exists at /dev/sr0. There’s nothing at /dev/sg3 even though the device node exists by default. I don’t understand why it’s claiming that those 2 devices are an optical drive. I’m only entering /dev/sr0 into the field. And the error message seems to imply that both devices are required for the single optical drive.

Also, I found an old json file from years ago by someone who did the same thing I’m trying to do, except they explicitly passed /dev/sr0 and /dev/sg6 as devices without creating fields for those 2 things:

                "opts": [
                    [
                        "--device",
                        "/dev/sr0"
                    ],
                    [
                        "--device",
                        "/dev/sg6"
                    ]],

I just checked the log file from the Handbrake rockon, and this is what it shows for the optical drive:

[cont-init   ] 54-check-optical-drive.sh: executing...
[cont-init   ] 54-check-optical-drive.sh: looking for usable optical drives...
[cont-init   ] 54-check-optical-drive.sh: found optical drive /dev/sr0, group 494.
[cont-init   ] 54-check-optical-drive.sh: terminated successfully.

I can access it in Handbrake by opening /dev/sr0 from within the image. The UID of the user that these images run as does belong to the cdrom group.

So I’m not sure if I’m passing the device node to the MakeMKV image in an incorrect way, or what other issue might be at play.

3 Likes

I will check it out on my test setup and report back here.

2 Likes

I am getting the same message as you do. Looking at the code in the docker file I can see, that the script is checking for the optical drive and then tries to construct a group using the ‘stat’ command. Interestingly, it should come back as 494 as well, but it never gets that far and what we can see from the script output it looks at the second column (showing the drive group, in my case /dev/sg6, since I have 6 disks in all on that VM sg0-sg5) but no group.

Considering the scsi naming conventions:

the /dev/sg6 represents the generic scsi layer, and I guess, here the author requires both the actual device as well as the associated scsi layer that exposes the drive to the container. Again, not sure why that is.

So, adding the generic scsi layer will resolve this here:

[cont-init   ] 54-check-optical-drive.sh: executing...
[cont-init   ] 54-check-optical-drive.sh: looking for usable optical drives...
[cont-init   ] 54-check-optical-drive.sh: found optical drive [/dev/sr0, /dev/sg6], group 494.
[cont-init   ] 54-check-optical-drive.sh: terminated successfully.

What i did find though, if entering the associated generic scsi layer only (instead of the dvd drive) it will also install, the logs will throw a warning though:

[cont-init   ] 54-check-optical-drive.sh: executing...
[cont-init   ] 54-check-optical-drive.sh: looking for usable optical drives...
[cont-init   ] 54-check-optical-drive.sh: found optical drive [/dev/sr0, /dev/sg6], group 494.
[cont-init   ] 54-check-optical-drive.sh: WARNING: for best performance, the host device /dev/sr0 needs to be exposed to the container.
[cont-init   ] 54-check-optical-drive.sh: terminated successfully.

Unfortunately, when I pull up the WebUI after clicking through a couple of things, it tells me the app is too old and disconnects the whole thing. I do catch a glance at some dvd drive I think …

So, you have to test and see whether that works instead. Otherwise, I’d create the json with both devices (dvd and scsi layer) to enter.

Since the author is using the same script/approach for these things, I compared the scripts between handbrake and makemkv. the handbrake one seems greatly simplified, if you want to take a look:

Handbrake:

vs.MakeMKV:

There is an issue open (albeit for QNAP):

but I think it doesn’t address the symptoms you and I have been seeing. I would recommend to open an issue over there, and ask why the two scripts are different, especially if you really only want to expose a single DVD-drive to the container.

For reference, here’s my version with both devices included:

{
    "MakeMKV": {
        "containers": {
            "makemkv": {
                "image": "jlesage/makemkv",
                "launch_order": 1,
                "devices": {
                    "opticaldrive": {
                        "description": "Optional: path to optical drive device (e.g., DVD drive at /dev/sr0).Optical drives usually have /dev/srX as device. E.g., the first drive is /dev/sr0, the second /dev/sr1, etc. Leave blank if not needed.",
                        "label": "Optical Drive"
                    },
                    "opticalgenericscsi": {
                        "description": "Optional: if optical drive field has been filled, also its associated generic scsi layer path has to be entered. Generic scsi layers usually have /dev/sgX as device. For this use, the X will be the number of other hard drive +1, e.g. if there are 5 harddrives, they will be assigned /dev/sg0 to 5, and the dvd will have /dev/sg6. This can be also verified with the lsscsi utility.",
                        "label": "Optical Drive Group"
                    }
                },
                "ports": {
                    "5800": {
                        "description": "WebUI port default 5810",
                        "host_default": 5810,
                        "label": "WebUI port",
                        "protocol": "tcp",
                        "ui": true
                    }
                },
                "volumes": {
                    "/config": {
                        "description": "Choose a Share for configuration.",
                        "label": "Config"
                    },
                    "/storage": {
                        "description": "Choose a Share for Storage",
                        "label": "Data Storage"
                    },
                    "/output": {
                        "description": "Choose a Share for Output",
                        "label": "Output"
                    }
                },
                "environment": {
                    "USER_ID": {
                        "description": "Enter a valid UID to run MakeMKV as. It must have full permissions to all Shares mapped in the previous step.",
                        "label": "UID to run MakeMKV as.",
                        "index": 1
                    },
                    "GROUP_ID": {
                        "description": "Enter a valid GID to use along with the above UID. It (or the above UID) must have full permissions to all Shares mapped in the previous step.",
                        "label": "GID to run MakeMKV as.",
                        "index": 2
                    },
                    "AUTO_DISC_RIPPER": {
                        "description": "When set to 1, the automatic disc ripper is enabled.",
                        "label": "AUTO DISC RIPPER",
                        "index": 3
                    },
                    "AUTO_DISC_RIPPER_EJECT": {
                        "description": "When set to 1, disc is ejected from the drive when ripping is terminated.",
                        "label": "AUTO EJECT",
                        "index": 4
                    },
                    "MAKEMKV_KEY":{
                        "description": "Makekmv key. Set to beta or own bought key",
                        "label": "MakeMKV key",
                        "index": 5
                    }
                }
            }
        },
        "description": "Rip DVD and Blu-ray.<p>Based on a custom docker image: <a target='_blank' href='https://hub.docker.com/r/jlesage/makemkv'>https://hub.docker.com/r/jlesage/makemkv</a>, available for amd64 and arm64 architecture.</p>",
        "ui": {
            "slug": ""
        },
        "volume_add_support": true,
        "website": "https://www.makemkv.com/",
        "version": "1.0"
    }
}

To test just with the scsi layer I took out the first device and ran it…

2 Likes

Thank you for that info! The “App too old” thing is resolved by actually entering the MakeMKV beta license key instead of typing in “beta” like the directions state. I don’t know why, but typing in “beta” just doesn’t work.

I’ll give this a try and see how it goes.

3 Likes

Your edits to the json file work perfectly. It’s mostly an annoyance that people have to figure which 2 devices to pass, and that process isn’t intuitive. It sounds like it should be whichever /dev/sgX is greatest. I’ve started a discussion on github for that docker image to get more information.

Thank you!

3 Likes

So upon further research, it looks like the reason behind needing to pass 2 devices for one optical drive is that this is necessary to get the LibreDrive firmware functionality to work. This custom optical drive firmware is what enables MakeMKV to read commercial Blu-Ray and UHD discs. Part of the process involves sending a temporary blob to the firmware, almost like a mini, temporary firmware update that lasts until the drive is powered down. I do have LibreDrive flashed to my optical drive, and that’s kinda the whole point of using MakeMKV, so I guess it makes sense. Just mildly complicated, since the only way to figure out which device nodes need passing is to look at the Docker installation logs (docker logs makemkv), see which device nodes it wants, then uninstall the image and re-install it with the proper devices.

3 Likes

Interesting, and thanks for getting more info on that.

If you feel so inclined you could submit this Rockon to the repository.