木偶 file_line 按特定顺序排列

Puppet file_line in specific order

我正在尝试向 /etc/profile 添加三个系统强化线:

TMOUT=43200
readonly TMOUT
export TMOUT

当然,这些行需要按此特定顺序排列,而且我还必须预料到文件会乱七八糟且顺序错误。 我无法使用模板,因为有些主机具有无法更改的自定义配置文件。所以我必须能够附加这三行

所以我在清单中写了这个:

file_line { 'TMOUT':
  path     => '/etc/profile',
  ensure   => present,
  line     => 'TMOUT=43200',
  multiple => true,
  before   => 'readonly TMOUT',
  match    => '^TMOUT',
}
file_line { 'readonly TMOUT':
  path     => '/etc/profile',
  ensure   => present,
  line     => 'readonly TMOUT',
  multiple => true,
  before   => 'export TMOUT',
  after    => '^TMOUT=43200',
  match    => '^readonly TMOUT',
}
file_line { 'export TMOUT':
  path     => '/etc/profile',
  ensure   => present,
  line     => 'export TMOUT',
  multiple => true,
  after    => '^readonly TMOUT',
  match    => '^export TMOUT',
}

Puppet 以正确的顺序创建行,但是当我编辑文件并更改顺序时,它在重新运行期间不会得到更正,例如

readonly TMOUT
export TMOUT
TMOUT=43200

我是不是弄错了,还是我必须换成其他东西,比如 Augeas?

提前致谢

TL;DR

你基本上有三个选择:尝试创建有序的依赖关系(这不是真正的 Puppet 方式),创建复合语句,或者使用 /etc/profile.d 如果您的发行版支持它。虽然没有单一的 "best" 方法来处理这个问题,但复合语句或声明可能是最简单的解决方案。

顺序依赖

Puppet 不保证大多数操作的顺序,除非您明确声明依赖关系。以下内容未经测试,但可能对您有用。

file_line { 'set TMOUT':
  ensure => present,
  path   => '/etc/profile',
  line   => 'TMOUT=43200',
  match  => '^TMOUT',
} ->
file_line { 'export TMOUT':
  ensure => present,
  path   => '/etc/profile',
  line   => 'export TMOUT',
  after  => '^TMOUT=',
} ->
file_line { 'set TMOUT as readonly':
  ensure => present,
  path   => '/etc/profile',
  line   => 'readonly TMOUT',
  after  => '^export TMOUT',
}

这应该可以满足您的需求,但比需要的更脆弱。还有更强大的选择。

复合语句和变量声明

大多数(如果不是全部)与 Bourne 兼容的 shells 应该支持复合语句,因此您最好跳过单个原子行操作的顺序。例如:

file_line { 'profile TMOUT':
  ensure => present,
  path   => '/etc/profile',
  line   => 'TMOUT=43200; export TMOUT; readonly TMOUT',
  match  => '^TMOUT',
}

更好的是,使用 shell 的 declare synax 一次操作即可完成所有工作!例如:

file_line { 'profile TMOUT':
  ensure => present,
  path   => '/etc/profile',
  line   => 'declare -r -x TMOUT=43200',
  match  => '^TMOUT',
}

注意:只读变量仍然可以在没有直接设置只读属性的子shell中赋值。这就是它的工作方式。

将文件放入 Profile.d

在支持它的发行版上,使用 /etc/profile.d 几乎总是比在 [= 这样的单一脚本中胡闹更好的选择59=]。它也不太可能被其他脚本、系统更新等破坏。但是,有一些注意事项,我在下面注明。

# Create your snippet in the /etc/profile.d directory.
file {'/etc/profile.d/tmout.sh':
  ensure => present,
  content => "TMOUT=43200\nexport TMOUT\nreadonly TMOUT",
} ->

# Remove the lines in /etc/profile if they exist.
file_line { 'profile TMOUT':
  ensure            => absent,
  path              => '/etc/profile',
  match             => 'TMOUT',
  match_for_absence => true,
  multiple          => true,
}

这里有一些注意事项:

  1. 存在微妙的竞争条件(即使使用依赖链),因为更改是顺序的而不是原子的。可能有一个小的window TMOUT 被定义在多个地方。
  2. 因为 profile.d 是特定于供应商的,除非您对其进行配置,否则它可能根本不受支持(甚至可能不存在)。检查您的分发文档。
  3. 同样,由于 profile.d 是特定于供应商的,因此 profile.d 中脚本的来源顺序可能会有所不同。它们通常在主要 /etc/profile 脚本之后获取,并且设置相同值的多个脚本的存在会使结果不确定。