-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
shell_command: Execute a linux command/script from within Klipper. #2173
Conversation
Thanks. My high-level feedback is that I'm a bit leery of doing this because of security and general stability concerns. The code itself looks fine to me. I'm not sure about the high-level implications though (eg, privilege escalation, system resource management, etc.). Is there a particular use-case that this functionality is designed to address? Maybe there are alternative solutions. -Kevin |
Hi Kevin, this was implemented at the request of a couple of Voron users. The examples they provided were things such as issuing push notifications and controlling LEDs from the Pi. These things could be implemented with extras modules, I think for them it was more an issue of flexibility. I warned them that there could be security implications. I attempted was to make it as safe as possible by requiring the command to be configured in printer.cfg (rather than something like |
@Arksine @KevinOConnor I would love to have that feature so that I could shutdown properly my system through M81 macro (using Repetier Server) Sent with GitHawk |
I use this for controlling my WLED Esp32. So probing does nightrider sequence, red fading while heatup, green light for print done etc. Additionally I can ping my grafana dB for uptimes, filament usage, average speed, layertimes. Maybe Someone moar more creative has other ideas. |
I would like this too, to trigger GPIO pins (I use DWC instead of Octoprint) |
Ideally, it would be nice that arguments could be passed too. (I know this could be a greater security concern; sight...) Raspberry Pi GPIOs is a good example. My use case is that I'm building an temperature controlled enclosure. I would like the slicer (Cura) to pass an enclosure temperature (that depends on the filament). This feature would allow me to send the value to an enclosure controller. Ultimately, we need a way to send commands to the DWC host when the action cannot be done by the MCU... Those could be added to macros which, right now, my understanding can only control the MCU. |
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
3250e82
to
c9de7da
Compare
I have modified shell_command.py to behave as a dev utility rather than a prefix module. I modeled it after how gcode_macro creates templates. For example, if the developer wants to create a shell command, they could do the following: shell_command = self.printer.try_load_module(config, 'shell_command')
self.reboot_cmd = shell_command.load_shell_command('sudo reboot now')
self.shutdown_cmd = shell_command.load_shell_command('sudo shutdown now') Then to execute the command: self.shutdown_cmd.run(timeout=None, verbose=False) Setting the timeout to None makes it the command fire and forget, the process will be launched and run() will return. It is not possible for a fire and forget command to be "verbose", so regardless of the parameter passed verbose will be set to false. Its also possible for a developer to set their own output callback via the shell command's |
Thanks. Looks good to me. I think we should look to merge this along with the first set of code that utilizes it though. Cheers, |
Would a unit test not suffice here? |
Would it still be possible for me - as a user - to define shell commands as gcode? edit: I have managed to write my own pushover host module. sonoff/tasmota should also be easy to implement. |
Has this been merged with the main branch yet? |
This will be very helpfull for notification (domoticz ...) with execution of wget command |
+1 |
+1 |
+1 The concerns about security and priv esc are valid, but lets face it, the printers should not be public facing anyways and should only be accessible via secure gateways (ssh, vpn, reverse proxy with authentication, etc). |
Would love to to see this happening. |
This should go back so that it lets users defined shell_commands in the config file again because the functions to run shell commands internally in klippy is trivial. The real power is letting users define their own cmd to call. Eric if you do not mind I would like to add template support and a filter extension to Jinja2 for safe quoting of shell args similar to Ansible. I can create a competing pull request starting from the commit above if that is not stepping on your toes. Ansible example of a shell quote filter for Jinja2 ~ line 111: The from a security point of view because Klipper's config is not accessible to run time changes that makes it akin to defining functions in code and recompiling. Users should be conditioned to secure their config files anyways because of the nature of the machines they run and the harm it could cause if misconfigured. What is the problem is other projects exposing the config file via a web interface which may or may not be protected with a user accounts, encryption, etc. To mitigate the above we could add a cli arg to enable this feature and that arg would usually to be provided in "/etc/default/klipper" so it isn't web accessible. Then if shell_commands are enabled, klipper could refuse to start if the main config file isn't owned by a certain user with more restrictive permissions. Something like chown klipper:klipper printer.cfg; chmod 664 printer.cfg. Then the pi user or a general web server user could read the file for display in the UI but not write changes. Users would need to ssh and sudo editor or cp a new versions and restart klippy. Openvpn, Ssh and Postgresql are a few projects I know of that have similar protections for config files and runtime function definitions(Postgresql especially). These checks would only apply if shell_commands are enabled leaving the default behavior in tact. Other less related protections could be added to secure the /etc/default/klipper file as well. I can roll all of the above into a new PR but it will take some time:
|
I'm not quite ready for a full PR but here is a WIP of the above: Item number 4 was skipped in favor of just detecting the existence of a shell_exec section and protecting the config files based on that. |
As there doesn't seem to be a need for this PR I'm going to go ahead and close it. Using the built in |
Sorry to reshuffle a closed issue, but it's not clear to me what the workaround is. In my case, having the 3d printer in the basement, I keep the light off. I then use an app on my phone to turn an IP camera's IR light on before heading to Fluidd where I get the stream via MJPEG. It would be nice to have a couple of macros assigned to a couple of wget's turning the IR light on/off without having to leave Fluidd. |
Basically this means that we have to either fork this or just put that single shell file into the extras folder. |
I have been using this for a while now and it's very helpful. I have defined 6 IP camera API calls via curl under 6 gcode_shell_command sections which I then group in 2 macros. The first turns the IR led on, points the camera to the printer, zooms in.
|
Here's the script: Just place it under your Here's a sample config: |
The shell_command module allows a user to run a linux command via gcode. The command is launched using subprocess.Popen, then Popen.poll() is checked every 50ms, this allows for the command's execution to yield cooperatively with the Reactor. If the command takes longer than the configured
timeout
to execute then the process is forcibly terminated.If
verbose
is set to True the output from the command is forwarded to the terminal.Example Command:
Octoprint's Output:
Signed-off-by: Eric Callahan arksine.code@gmail.com