Как стать автором
Обновить
2661.57
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Ненавижу тебя, CUPS

Время на прочтение9 мин
Количество просмотров20K

Продолжение импортозамещения. Рабочие станции мы уже раскатываем в автомагическом режиме, пришло время и о периферии подумать — юзеры, вернее, их руководители, хотят видеть результаты трудов в твёрдом виде на экобумаге.

Прежде всего опишу правильную конфигурацию инфраструктуры сетевой печати в корпорации. Это важнейшая составляющая наших граблей. Заодно зацените схему, делал в отечественном редакторе Автограф под линукс :)



Что и почему (рассматриваем схему справа налево):

  1. Выносим принтеры (вернее, вынесли уже давно) в отдельный сегмент сети и ограничили туда доступ файрволами. Старые принтера и МФУ-шки умеют небезопасные протоколы типа telnet, ftp и т.д. которые уже не лечатся никакими прошивками. С учётом ухода сервиса производителей, эта участь постигнет и более современное железо — прошивки достать уже проблематично, а иногда даже опасно.
  2. В сегмент принтеров имеют доступ только админы и принт-сервер. Так проще наладить учёт печати и разграничить доступ — энтерпрайз это обожает.
  3. Локальный cups на клиентском рабочем месте (линуксовом) — это особенности системы печати. Можно обойтись и без него, достаточно в файле /etc/cups/client.conf указать адрес сервера печати в директиве ServerName , но тогда теряется возможность работы с локальными принтерами и летит к чертям унификация рабочих мест, энтерпрайз это ненавидит.

Про конкурентов
В винде кстати всё примерно также, только чуток гибче, отказ от локального спула не глобальный, а для каждого принтера отдельно


Итак, между нашим отечественным офисным пакетом и принтером находятся 2 купса (подозреваю, что в некоторых случаях и три, т.к. с большой долей вероятности в принтере тоже крутится маленький линукс со своим купсом на борту)

▍ Теперь бегло рассмотрим теорию, как это работает


Офисный специалист нажимает кнопочку печать, и прикладное программное обеспечение отправляет на печать некий готовый материал — это может быть картинка (image/png), файл в формате postscript (application/postscript), pdf-файл (application/pdf), неважно. Вот этот материал загоняется в спул печати. Причём классические lp*-утилиты и библиотеки давным-давно подменены купсом. То есть купс либо принимает информацию в свой спул и обрабатывает, либо (вариант с одной зелёной стрелочкой на схеме) прозрачно льёт купсу принт-сервера.

CUPS на стороне клиента приступает к работе. Условно будем считать, что работаем с файлом, ну хорошо, не условно, в юниксах всё файл :)

  • Файл принимается.
  • Разглядываем его исходный формат, либо нам его сообщили, либо определили сами (man mime.types).
  • Прикидываем в каком формате его надо отдать (в файле описания ppd, потом придётся рассказать).
  • Преобразовываем различными фильтрами (filters).
  • Решаем, куда его надо отдать (backend).
  • Передаём.
  • Дожидаемся результата печати и сообщаем его в место получения файла, а если что-то пошло не по плану, также доводим до сведения отправителя файла.

На сервере печати CUPS вытворяет то же самое.

Вся эта теория имеется в документации CUPS, но несколько бестолково изложено, либо я не был готов сразу вчитать и систематизировать такое количество информации. Совсем немного содержится в статье википедии на русском языке. А теперь сравните её с английской страничкой. Вся информация внятно изложена на 3-х экранах и двух схемах (схема фильтрации — шикарна).

▍ С общей теорией покончено, пора приступать к практике


Как развернуть CUPS на рабочей станции/сервере и добавить принтеры я писать не буду, т.к. это реально просто, и в сети информации достаточно. Отмечу только, что url вида ipp://printer/ipp внутри купса будут развёрнуты в http://printer:631/ipp (а также ipps->https) и могут всюду использоваться равноценно (пруф Chapter 1: Overview of IPP). Используйте как удобнее или больше нравится.



Сначала будем подключать бодрого старичка HP m3027MFP, предположительно родившегося в 2010 году (на картинке из интернета он белый, но все сохранившиеся экземпляры уже жёлтого цвета). К слову, драйверов в системе (файлы .PPD) аж целых 5 штук.

Начинать опять будем справа-налево, т.е. сначала пробуем печать с сервера (у купса для этого имеется специальный тест в интерфейсе администратора). Ставим драйвер "HP LaserJet M3027 MFP Postscript (recommended)", надпись в скобочках внушает доверие, далее пускаем тест и убеждаемся, что всё отлично работает и первая тестовая страничка готова — их у нас будет много.

На клиента водружаем драйвер "HP LaserJet M3027 MFP pcl3, hpcups 3.15.9", по идее ведь неважно, что серверу печати скармливаем? Пусть разбирается. И тут первый облом, трофея мы не дождались. На сервере начинаем разглядывать логи (уровень детализации задаётся в файле /etc/cupsd.conf опция LogLevel). Для этого в админке купса на страничке принтера узнаём номер задания, далее с этим номерком обращаемся к journalctl:

$ journalctl -u cups JID=43

или если у нас журнал ведётся в файлах:

# grep Job\ 43 /var/log/cups/error_log

Смотрим и ничего криминального не замечаем. Видим, что на вход пришло application/vnd.cups-raster, навешано 5 фильтров, один из которых бэкэнд, все отрапортовали "exited with no errors." В конце издевательская надпись "Job completed".

авг 30 14:04:03 cupsd[6597]: [Job 43] Applying default options...
авг 30 14:04:03 cupsd[6597]: [Job 43] Adding start banner page "none".
авг 30 14:04:03 cupsd[6597]: [Job 43] Queued on "HP3027" by "alef13".
авг 30 14:04:03 cupsd[6597]: [Job 43] File of type application/postscript queued by "alef13".
авг 30 14:04:03 cupsd[6597]: [Job 43] Adding end banner page "none".
авг 30 14:04:03 cupsd[6597]: cupsdCheckJobs: Job 43 - dest="HP3027", printer=(nil), state=3, cancel_time=0, hold_until=1660043943, kill_time=0, pending_cost=0, pending_timeout=0
авг 30 14:04:03 cupsd[6597]: [Job 43] time-at-processing=1660043043
авг 30 14:04:03 cupsd[6597]: [Job 43] 4 filters for job:
авг 30 14:04:03 cupsd[6597]: [Job 43] gstopdf (application/postscript to application/pdf, cost 0)
авг 30 14:04:03 cupsd[6597]: [Job 43] pdftopdf (application/pdf to application/vnd.cups-pdf, cost 66)
авг 30 14:04:03 cupsd[6597]: [Job 43] gstoraster (application/vnd.cups-pdf to application/vnd.cups-raster, cost 99)
авг 30 14:04:03 cupsd[6597]: [Job 43] hpcups (application/vnd.cups-raster to printer/320-HP3027, cost 0)
авг 30 14:04:03 cupsd[6597]: [Job 43] job-sheets=none,none
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[0]="HP3027"
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[1]="43"
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[2]="alef13"
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[3]="Test Page"
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[4]="1"
авг 30 14:04:03 cupsd[6597]: [Job 43] argv[5]="job-uuid=urn:uuid:ad538100-5dab-34bb-7a54-be4bcf445b96 job-originating-host-name=192.168.1.13 date-time-at-creation= date-time-at-processing= time-at-creation=1660043043 time-at-processing=1660043043"

...

авг 30 14:04:03 cupsd[6597]: [Job 43] backendWaitLoop(snmp_fd=5, addr=0x562c4243edc8, side_cb=0x562c4240c2e0)
авг 30 14:04:03 cupsd[6597]: [Job 43] No pages left, outputting empty file.
авг 30 14:04:03 cupsd[6597]: [Job 43] PID 7098 (/usr/lib/cups/filter/gstopdf) exited with no errors.
авг 30 14:04:03 cupsd[6597]: [Job 43] Input is empty, outputting empty file.
авг 30 14:04:03 cupsd[6597]: [Job 43] Input is empty, outputting empty file.
авг 30 14:04:03 cupsd[6597]: [Job 43] PID 7099 (/usr/lib/cups/filter/pdftopdf) exited with no errors.
авг 30 14:04:03 cupsd[6597]: [Job 43] PID 7100 (/usr/lib/cups/filter/gstoraster) exited with no errors.
авг 30 14:04:03 cupsd[6597]: [Job 43] PID 7101 (/usr/lib/cups/filter/hpcups) exited with no errors.
авг 30 14:04:03 cupsd[6597]: [Job 43] PID 7102 (/usr/lib/cups/backend/ipp) exited with no errors.
авг 30 14:04:03 cupsd[6597]: [Job 43] time-at-completed=1660043043
авг 30 14:04:03 cupsd[6597]: [Job 43] Job completed.

Если ещё разок глянуть чуть внимательнее, то видны строчки «Input is empty, outputting empty file.». Идентифицировать, кто конкретно их вписал, нет возможности, но мы почти точно уверены, что это фильтры. И становится понятно, почему принтеру ничего не досталось. Сволочи они.

В общем, связка получилась какая-то кривая. Ставим клиенту драйвер Postscript, рекомендованный. И знаете, оно работает.

Немного поразмышляв, придумываем себе правило номер 1 — слишком много фильтров это плохо. Надо постараться сделать минимальное количество преобразований файла при печати. Т.е. на стороне клиента и на сервере желательно ставить одинаковые драйвера.
Про hplip
Пишут что лучшие результаты даёт драйвер hplip производства Хьюлита-Паккарда. По сути это плугин к купс, и CUPS показывает его как установленный принтер. Строчку для подключения формируем утилитой hp-makeuri, только учтите, что с сетевыми принтерами она работает через протокол JetDirect (tcp/9100). Именно недоступность данного сетевого взаимодействия на моём стенде не дало дописать сюда ещё пару страниц.



Следующий пациент — рикошечка 2352. Это такое относительно небольшое (видал и поболе), но и не маленькое (дома уже не поставить) МФУ. Соответствующих драйверов в коробку с линуксом не положили :(
Про драйвера
Собственно драйвер для конкретной модели принтера понятие несколько надуманное. Сделано для облегчения жизни конечного пользователя, чтобы не вгонять его в сомнения о правильности действий при настройке оборудования.

На самом деле команд/протоколов общения с принтерами весьма ограниченное количество, и различаются железяки между собой прежде всего дизайном и некоторыми дополнительными возможностями: дуплексы, лотки, сшиватели, жесткие диски, софт, встроенные шрифты и т.д.

Вот это всё и описано в «драйверах», в файлах с расширением PPD (Adobe PostScript Printer Description). Это обычный текстовый файл (довольно толстый из-за локализации) с описанием возможностей конкретной модели оборудования. А все стандартные низкоуровневые управляющие команды языков (PCL, PS, HP-GL, ESC/P и т.д.) печатной техники система уже давно знает.

Также, началось активное продвижение IPP Everywere, т.е. один драйвер на всё. Не сильно погружался, но думаю, что это либо сильно упрощённая и урезанная по своим возможностям печать, либо опрос у конечного оборудования какие суперспособности оно имеет. В любом случае пока мимо — первое неудобно, второе в больших конторах пока не применимо из-за возраста железа.
Не беда, файлы ppd для данной МФУ находятся на openprinting и разложены по каталогам PXL, PS,… Заглядывайте при необходимости, там ещё есть и не только для Ricoh.

Как обычно заводим на сервере очередь (в терминах купса это принтер...) и подгружаем туда
«драйвер» для Postscript. Мы так уже привыкли. Запускаем тест печати, глянули логи — всё отлично, идём к аппарату.

А там пусто, неужели кто-то утащил наш документ? Опять читаем логи сервера и ничего подозрительного там тоже не видно, всё отработано и передано нашему аппарату. Штош, полистаем сенсорный экран на МФУ. Видим, что наши тестовые странички улетели в журнал ошибок с кодом 91 — ошибка данных. Лечить это мы не будем, т.к. официального сервиса нет и не предвидится.

Помните, у нас ведь в запасе ещё пара-тройка драйверов — пробуем сначала мягкие методы. Берём ppd файл из каталога PXL, устанавливаем, запускаем проверочную страничку и получаем желаемую распечатку. Переходим на клиента. Вспоминаем наше правило №1 и ставим драйвер «PXL», который сразу же отказался сотрудничать :)

На сервере печати задание вывалилось с ошибкой фильтра.
Про фильтры
Фильтр это фактически основная фишка купса. Конечно они были и раньше, например мне давным-давно приходилось через пайпы фильтровать файлы на вход lpr, но купс спрятал все эти кишочки от пользователя и теперь видим их только мы, сисадмины. Как применять фильтры определяет файл mime.convs — читаем man, ищем в системе файлы '.convs'. Всё просто и понятно, вот только значение поля cost неочевидно. В интернетах пишут, что оно определяет «цену» фильтра от 0 до 100. Предположу что если найдётся цепочка фильтров преобразований с суммарной стоимостью менее чем фильтр, делающий то-же самое, но в одиночку, то купс предпочтёт прогнать данные именно через эту цепочку.

Что делать если купс в логах рисует фильтры, которые в конфигурационных файлах вы не нашли? Правильно, заглянуть в файл PPD — там тоже это встречается :)

Ниже привожу кусочек из файла Ricoh-Aficio_MP_2352_PXL.PPD

*cupsVersion:      1.1
*cupsManualCopies: False
*cupsCommands:     ""
*cupsFilter: "application/vnd.cups-postscript 0 foomatic-rip"
*cupsFilter: "application/vnd.cups-pdf 0 foomatic-rip"

*FoomaticRIPCommandLine: "(printf '\033%%-12345X@PJL\n@PJL JOB\n@PJL SET COPIES=&copies;\n'%G|perl -p -e "s/\x26copies\x3b/1/");
(gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -dNOINTERPOLATE %B%A%C %D%E | perl -p -e "s/^\x1b\x25-12345X//" | perl -p -e "s/\xc1\x01\x00\xf8\x31\x44/\x44/g");
(printf '@PJL\n@PJL EOJ\n\033%%-12345X')"
*End

*FoomaticRIPUserEntityMaxLength: 8

Дальше чтение логов как на стороне клиента, так и на стороне сервера, осмотр файла в спуле, ну и краткий вывод — сервер ожидал на входе vendor.cups-postscript, а получил что-то ему неизвестное. Ну как неизвестное — я посмотрел внутренности файла в спуле, вполне себе postscript, только в начале добавка PJL (язык управления заданиями). Вот это-то и не понравилось фильтру.

авг 30 16:18:13 cupsd[6597]: [Job 66] Cannot process \"/var/spool/cups/d00066-001\": Unknown filetype.
авг 30 16:18:13 cupsd[6597]: [Job 66] Process is dying with \"Could not print file /var/spool/cups/d00066-001
авг 30 16:18:13 cupsd[6597]: [Job 66] \", exit stat 2

Ставим на клиента чистый драйвер postscript, от которого отказались на сервере — работает. Отсюда правило №2 — правила №1 не существует, есть только рекомендация №1 :)

Велик соблазн отрубить на сервере все эти драйвера / фильтры и использовать raw-очереди — всё равно клиент уже подготовил данные в необходимом формате. Но в логах сервера получаем запись «Queue printer is a raw queue, which is deprecated.», которая как-бы намекает, что это быстрое решение, но не правильное. В свежую систему тащить легаси некомильфо. В списках рассылки купса этому есть пояснение.

И напоследок, ещё одна довольно полезная, на мой взгляд, опция: в файле /etc/cups/cupsd.conf найдите JobPrivateValues и поставьте значение none. Таким образом, в интерфейсе управления cups будут отображаться нормальные значения имени пользователя и названия задания.

▍ Финал


Вот коротенько и всё, что я хотел написать про CUPS, а также где и как разбираться с отказами печати. И, разумеется, этими двумя случаями траблы не исчерпываются — впереди ещё много железа и софта с их уникальными глюками. Ну а если кто помнит старину ГГ, заголовок статьи — это не проклятие, а весьма душевное приветствие :)
Конкурс статей от RUVDS.COM. Три денежные номинации. Главный приз — 100 000 рублей.
Теги:
Хабы:
Всего голосов 35: ↑34 и ↓1+54
Комментарии28

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds