调试Ubuntu 16.04服务器的preseed/late_command:找不到tee命令或目录不存在。

我正在尝试在一个Ubuntu 16.04服务器上运行以下的preseed文件(在packer构建过程中):
d-i preseed/late_command string \
in-target mkdir -v -p -m 0440 "/etc/sudoers.d"; \
in-target echo "%vagrant ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers.d/vagrant; \
in-target echo "Defaults:vagrant !requiretty" | tee -a /etc/sudoers.d/vagrant; \
in-target chmod 440 /etc/sudoers.d/vagrant;

在 /var/log/installer/syslog 中,我可以看到以下错误:
log-output: sh:
log-output: tee: not found

当我将"| tee -a"部分更改为">>",如下所示:
d-i preseed/late_command string \
in-target mkdir -v -p -m 0440 "/etc/sudoers.d"; \
in-target echo "%vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/vagrant; \
in-target echo "Defaults:vagrant !requiretty" >> /etc/sudoers.d/vagrant; \
in-target chmod 440 /etc/sudoers.d/vagrant;

它突然开始抱怨找不到目录,却没有提及mkdir这一行代码——所以它既没有创建目录,也没有找到它。
log-output: sh: can't create /etc/sudoers.d/vagrant: nonexistent directory
log-output: sh: can't create /etc/sudoers.d/vagrant: nonexistent directory
log-output: chmod:
log-output: cannot access '/etc/sudoers.d/vagrant'
log-output: : No such file or directory

我一直在github上研究其他脚本。另外,我还在preseed.cfg文件中添加了以下行:
d-i pkgsel/include string openssh-server coreutils wget sudo

我甚至尝试将coreutils作为目标命令安装,以确保tee可用。已经花了几天的时间,一次又一次地重建ubuntu,只发现syslog中出现相同的错误。如果有人能给予一些指导 - 这一定是一些简单的问题,但我没有看到...
6个回答

两件事:
1. 当执行`in-target some_command > /some/path`时,重定向不会发生在目标内部。你需要这样做:`in-target --pass-stdout some_command > /target/some/path`
2. `in-target`命令将命令的输出重定向到日志文件中。因此,默认情况下无法从`in-target`中重定向输出。你需要使用`--pass-stdout`参数来使用`in-target`。
in-target --pass-stdout echo "hello" > /target/root/hello.txt

这将创建一个文件/target/root/hello.txt,内容为'hello'

来源: https://salsa.debian.org/installer-team/debian-installer-utils/-/blob/3e67bc7987eb4a9cdff5fe8d1084e612fe7bb48f/README

in-target: 在/target中运行指定的命令,并返回其退出状态。使用debconf passthrough前端来使用cdebconf在安装程序中提问debconf问题非常有用。这对于运行像dpkg-reconfigure、debconf-apt-progress和tasksel这样的任务特别有用。log-output实用程序用于记录任何输出;如果以--pass-stdout选项调用in-target,则log-output将予以尊重。


in-output是一个脚本,你可以在"<installer.iso>/install.amd/initrd.gz/initrd/bin"目录中找到。 - Antonio Rizzo

似乎无法在in-target中使用echo命令。为了解决这个问题,请尝试以下方法(在Ubuntu 18.04中已经尝试过):
d-i preseed/late_command string \
    echo "some text" >> /target/path/to/file.ext ; \
    in-target [some-other-command-in-target]

注意:
- 在这行之前不要使用`in-target` - 在真实路径之前使用`/target` - 在其他命令中,你可以在大多数情况下在这行之前使用`in-target`

1这应该是被接受的答案。在 Ubuntu 19.10 服务器 amd64 上工作(非实时)。 - moeiscool
同意@moeiscool的观点。应该接受这个答案。 - DOMZE

如果您喜欢使用Debian安装程序,在17.10.1服务器上,当将SSH公钥添加到authorized_keys时,这对我很有效。您必须确保事先创建了.ssh目录。
d-i preseed/late_command string in-target /bin/sh -c 'echo "my string" >> /home/username/.ssh/authorized_keys';

我花了大约一天的时间来调试这个问题,并尝试了以下几种方法,结果各不相同。如果有更详细的文档说明在Debian安装程序中使用哪个shell来执行各种非/ 'in-target'指令,那就太好了,但我可能没有找对地方。
  1. 使用普通的in-target echo命令,指定了普通的authorized_keys路径:

    in-target echo "my string" >> /home/username/.ssh/authorized_keys;
    

    在/var/log/installer/syslog中显示"目录未找到"。

  2. 使用普通的in-target echo命令,指定了目标机器的authorized_keys路径:

    in-target echo "my string" >> /target/home/username/.ssh/authorized_keys;
    

    在目标机器上生成一个空的authorized_keys文件,并且在查看/var/log/installer/syslog时,你会发现"my string"被输出到stdout。

  3. 使用显式的in-target命令,带有"sh -c..."参数,并指定了目标机器的authorized_keys路径:

    in-target /bin/sh -c 'echo "my string" >> /target/home/username/.ssh/authorized_keys';
    

    在/var/log/installer/syslog中显示"目录未找到"错误。

希望这能节省一些时间和调试!

你可以使用Ubiquity代替Debian-Installer(https://wiki.ubuntu.com/Installer/FAQ),这样你的命令就会是:
ubiquity  ubiquity/success_command string \
 in-target /bin/mkdir -v -p -m 0440 "/target/etc/sudoers.d"; \
 in-target /bin/echo "%vagrant ALL=(ALL) NOPASSWD: ALL" >> /target/etc/sudoers.d/vagrant; \
 in-target /bin/echo "Defaults:vagrant !requiretty" >> /target/etc/sudoers.d/vagrant; \
 in-target /bin/chmod 440 /target/etc/sudoers.d/vagrant

它解决了指向正确位置(/target/etc/)报告的“没有该文件或目录”的问题。

这不是一个命令,而是用于您的preseed文件的配置指令。它通过指向正确的位置(/target/etc/)解决了“没有此文件或目录”的问题。 - RAAD
请编辑您的回答以添加该信息。 - guntbert

在 in-target 指令中,echo 会正常工作。你需要使用反引号(`)将其包裹起来。例如,我想从 preseed 文件更新我的机器主机名:

in-target hostname echo "ubn"$(lshw | grep -m 1 serial | awk '{print tolower ($2)}')

反引号告诉 shell 将其作为一个命令运行。


如果你把 in-target 命令放在正确的位置,使用 tee 的原始尝试也会起作用...

d-i preseed/late_command string \
in-target mkdir -v -p -m 0440 "/etc/sudoers.d"; \
echo "%vagrant ALL=(ALL) NOPASSWD: ALL" | in-target tee -a /etc/sudoers.d/vagrant; \
echo "Defaults:vagrant !requiretty" | in-target tee -a /etc/sudoers.d/vagrant; \
in-target chmod 440 /etc/sudoers.d/vagrant;