NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
16.45k stars 12.95k forks source link

Declarative printer configuration fails if printer unavailable #78535

Open snicket2100 opened 4 years ago

snicket2100 commented 4 years ago

Describe the bug

Declarative printer management via hardware.printers.ensurePrinters is a great feature, the problem is that whenever I rebuild my configuration with my network printer not being available (switched off, or me being on a different network), ensure-printers.service fails.

[...]
warning: the following units failed: ensure-printers.service

● ensure-printers.service - Ensure NixOS-configured CUPS printers
   Loaded: loaded (/nix/store/xsigwnz8cxj4hcvkvl8344kxsgdpxfgn-unit-ensure-printers.service/ensure-printers.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Sun 2020-01-26 13:32:19 CET; 19ms ago
  Process: 14791 ExecStart=/nix/store/hkmgwdqx0768gdkilk510zfmx6qd5q1v-unit-script-ensure-printers-start (code=exited, status=1/FAILURE)
 Main PID: 14791 (code=exited, status=1/FAILURE)
       IP: 112B in, 464B out
      CPU: 10ms

Jan 26 13:31:49 xxx systemd[1]: Starting Ensure NixOS-configured CUPS printers...
Jan 26 13:32:19 xxx hkmgwdqx0768gdkilk510zfmx6qd5q1v-unit-script-ensure-printers-start[14791]: lpadmin: Unable to connect to "192.168.111.111:631": Operation now in progress
Jan 26 13:32:19 xxx systemd[1]: ensure-printers.service: Main process exited, code=exited, status=1/FAILURE
Jan 26 13:32:19 xxx systemd[1]: ensure-printers.service: Failed with result 'exit-code'.
Jan 26 13:32:19 xxx systemd[1]: Failed to start Ensure NixOS-configured CUPS printers.
Jan 26 13:32:19 xxx systemd[1]: ensure-printers.service: Consumed 10ms CPU time, received 112B IP traffic, sent 464B IP traffic.
warning: error(s) occurred while switching to the new configuration

A clear and concise description of what the bug is.

To Reproduce Steps to reproduce the behavior:

  1. Add a network printer to hardware.printers.ensurePrinters.
  2. Make sure the printer is not available.
  3. Run nixos-rebuild.
  4. See the error as above.

Expected behavior

It would be nice if ensure-printers.service was able to add/modify printers ignoring network connectivity errors. Unfortunately I couldn't find any option of lpadmin which would allow that :/

Metadata

 - system: `"x86_64-linux"`
 - host os: `Linux 5.4.13, NixOS, 20.03.git.4dbdc31 (Markhor)`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.3.2`
 - channels(root): `"nixos-20.03pre210300.05626cc86b8"`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixos`
aanderse commented 4 years ago

ping @florianjacob ... though to be honest this sounds like it is working as expected.

snicket2100 commented 4 years ago

yeah I agree it is disputable, just that currently it makes declarative printer management nearly impossible on any mobile computers

florianjacob commented 4 years ago

The thing is: My configuration is full of unavailable remote network printers of all sorts, IPP, remote cups, socket, even Canon's proprietary bjnp and everything rebuilds fine. :thinking:

@snicket2100 could you post your full printer & cups config? I guess something is different to mine, which causes your configuration to actually contact the printers on adding them, while mine doesn't.

snicket2100 commented 4 years ago

Hmm, it looks like just one IPP printer is enough to trigger this problem for me.

My ensure-printers-start script gets generated as follows:

#! /nix/store/x7hj5hp24flxbx6jnnws5rnjs31g0ybw-bash-4.4-p23/bin/bash -e
/nix/store/7xzpwwsasf0709nm7rs8nzf4jfxsw36k-cups-2.3.0/bin/lpadmin -p 'PRINTERNAME' -E \
   \
   \
  -v 'ipp://1.1.1.2' \
  -m 'everywhere' \
  -o 'PageSize'='A4'
/nix/store/7xzpwwsasf0709nm7rs8nzf4jfxsw36k-cups-2.3.0/bin/lpoptions -d 'PRINTERNAME'

It is the fist command that fails, if I do: /nix/store/7xzpwwsasf0709nm7rs8nzf4jfxsw36k-cups-2.3.0/bin/lpadmin -p 'PRINTERNAME' -E -v 'ipp://1.1.1.2' -m 'everywhere' manually it times out on contacting the printer: lpadmin: Unable to connect to "1.1.1.2:631": Operation now in progress.

I suspect it fails here https://github.com/apple/cups/blob/master/systemv/lpadmin.c#L1216, when called from here https://github.com/apple/cups/blob/master/systemv/lpadmin.c#L630 only for everywhere printers. Not entirely sure that it even has the chance to contact the cups server at that point, but in case it does this is my /etc/cups/cupsd.conf file:

Listen localhost:631

Listen /run/cups/cups.sock

DefaultShared No

Browsing No

WebInterface No

LogLevel info

DefaultAuthType Basic

<Location />
  Order allow,deny
  Allow localhost
</Location>

<Location /admin>
  Order allow,deny
  Allow localhost
</Location>

<Location /admin/conf>
  AuthType Basic
  Require user @SYSTEM
  Order allow,deny
  Allow localhost
</Location>

<Policy default>
  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job CUPS-Move-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>

  <Limit Pause-Printer Resume-Printer Set-Printer-Attributes Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After CUPS-Add-Printer CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>
    AuthType Basic
    Require user @SYSTEM
    Order deny,allow
  </Limit>

  <Limit Cancel-Job CUPS-Authenticate-Job>
    Require user @OWNER @SYSTEM
    Order deny,allow
  </Limit>

  <Limit All>
    Order deny,allow
  </Limit>
</Policy>

How is that different to your config @florianjacob ?

stale[bot] commented 3 years ago

Hello, I'm a bot and I thank you in the name of the community for opening this issue.

To help our human contributors focus on the most-relevant reports, I check up on old issues to see if they're still relevant. This issue has had no activity for 180 days, and so I marked it as stale, but you can rest assured it will never be closed by a non-human.

The community would appreciate your effort in checking if the issue is still valid. If it isn't, please close it.

If the issue persists, and you'd like to remove the stale label, you simply need to leave a comment. Your comment can be as simple as "still important to me". If you'd like it to get more attention, you can ask for help by searching for maintainers and people that previously touched related code and @ mention them in a comment. You can use Git blame or GitHub's web interface on the relevant files to find them.

Lastly, you can always ask for help at our Discourse Forum or at #nixos' IRC channel.

florianjacob commented 1 year ago

@snicket2100 Please excuse the enormous delay. The difference between my and your config is indeed that I do not have any IPP Everywhere printer, and your diagnosis seems right hat IPP everywhere printers cannot rebuild when they are offline.

From the current manpage of the lpadmin -m option:

Sets a standard PPD file for the printer from the model directory or using one of the driver interfaces. Use the -m option with the lpinfo(8) command to get a list of supported models. The model "raw" clears any existing PPD file and the model "everywhere" queries the printer referred to by the specified IPP device-uri. Note: Models other than "everywhere" are deprecated and will not be supported in a future version of CUPS.

The “queries the printer referred to by the specified IPP device-uri” specifically sounds like what you have experienced back then already. As the following deprecation note sounds quite concerning and might threaten the NixOS declarative printer configuration, I wanted to ask where you went from there and whether you found a solution that we might are able to integrate for whenever that deprecation notice actually becomes reality.

tobiasBora commented 1 year ago

Note that I also got bitten by this a while ago (so that is part of the reason why I don't use declarative printer management… too bad). In my case I was not using everywhere but a network printer based on dnssd:

  # It works fine, but it always try to reinstall the printer, even if we are not on the network...
  # So it breaks the switch.
hardware.printers.ensureDefaultPrinter = "MyLabPrinter";
hardware.printers.ensurePrinters = [
  {
    name = "MyLabPrinter";
    # Get this from "lpinfo -v" (or use localhost:631 the printers are the good ones)
    deviceUri = "dnssd://25-26%2F103%20MFP%20MyLab%20(color)%20%40%20cups._ipp._tcp.local/cups?uuid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx";
    # the path should be the the directories below $out/share/cups/model/
    # /nix/store/z0h1jwqw1k8pllkkvgpcqghwsgj1fz3m-hplip-3.19.1/share/cups/model/HP/hp-pagewide_color_e77650-e77660-ps.ppd.gz
    # To get the full list of drivers:
    # lpinfo -m | grep 77660
    # HP/hp-pagewide_color_765-ps.ppd.gz HP PageWide Color E77650-E77660 Postscript
    # HP/hp-pagewide_color_e77650-e77660-ps.ppd.gz HP PageWide Color E77650-E77660 Postscript
    # Only the 'second' driver has stapler enabled.
    model = "HP/hp-pagewide_color_e77650-e77660-ps.ppd.gz";
    location = "Printer_MyLab";
    ppdOptions = {
      PageSize = "A4";
    };
  }
];

Also, if PPD files are going to be deprecated in CUPS, how can we use advanced functionalities not provided by IPP everywhere?

dpolakovics commented 9 months ago

Hello,

i'm not sure if this fits in here, but i noticed the following with an IPP everywhere printer: When i use it with stateless it only works when i restart the service. At boot it becomes a "Local Raw Printer"

Without stateless it always becomes a Local Raw Printer

zoechi commented 7 months ago

For me it failed even when the printer was available.

With just avahi (without hardware.printers.ensurePrinters) the printer was found and working as IPP everywhere (Canon MG3600 series over WiFi).

rnhmjoj commented 6 days ago

At boot it becomes a "Local Raw Printer"

I noticed this as well. With certain printers CUPS seems to be generating a PPD file on-the-fly by querying the printer attributes via IPP, regardless of what "make/model" you have specified.

The solution would probably be to add the printer manually from the web UI, extract the generated PPD file from /var/lib/cups/ppd/ and configure it using lpadmin -P. It seems to work, but I haven't tested actually printing after this.

Note: Models other than "everywhere" are deprecated and will not be supported in a future version of CUPS.

I very much doubt the will do this: it will instantly break support for decades of printers. I can already see people raising their pitchforks.

IreneKnapp commented 4 days ago

this bug definitely went away for a while, or else there are conditions under which it doesn't manifest (perhaps it doesn't break unless the existing CUPS config changes?)

anyway, it's a problem again for me in 24.05, just in case mentioning that is useful to diagnosis or prioritization

rnhmjoj commented 1 day ago

I can confirm that my solution works. So:

  1. add the printer manually
  2. grab the generated ppd from /var/lib/cups/ppd
  3. add the following to your config:
services.printing.enable = true;

services.printing.drivers = lib.singleton (pkgs.linkFarm "drivers" [
  { name = "share/cups/model/myprinter.ppd";
    path = ./myprinter.ppd;
  }
]);

hardware.printers.ensurePrinters = [
  { name        = "my-printer";
    description = "some random printer";
    location    = "at home";
    deviceUri   = "ipps://my-printer.local:631/ipp/print";
    model       = "myprinter.ppd";
  }
];