[和訳] Updating 3.x Manifests for Puppet 4.x

次の和訳です。自分がPuppet4にそろそろ移行したいなと思ったので勝手に和訳しました。

http://docs.puppetlabs.com/puppet/4.2/reference/experiments_future.html
2015/10閲覧

***

いくつかの破壊的な変更がPuppet4.0で追加されています。以前Puppet3.xを使っていた場合は、新しい実装に合わせてマニフェストをアップデートする必要があります。このページではマニフェストを4.0互換にアップデートするために重要な手順を並べています。
> Several breaking changes were introduced in Puppet 4.0. If you previously used Puppet 3.x, your manifests will need to be updated for the new implementation. This page lists the most important steps to update your manifests to be 4.x compatible.

# すべてが正しい場所にあることを確認する
- `Make Sure Everything Is in the Right Place`

コードのディレクトリと重要なコンフィグファイルの場所が変更されました。それらが[どこに行ったかについて](http://docs.puppetlabs.com/puppet/4.2/reference/whered_it_go.html)のドキュメントを読み、ファイルが正しい場所にあることを確認してください。マニフェストのアップデートに挑戦するのはその後です。
> The locations of code directories and important config files have changed. Read about [where everything went](http://docs.puppetlabs.com/puppet/4.2/reference/whered_it_go.html) to make sure your files are in the correct place before tackling updates to your manifests.

# cronリソースを除去する前に、その安全性をダブルチェックする
- `Double-Check to Make Sure It’s Safe Before Purging cron Resources`

以前のバージョンでは、`{'cron': purge => true}`というリソースを使うことは現在Puppetを走らせているユーザー（たいていrootですが）に所属しているジョブを解除するだけのcronリソースでした。しかしPuppet4ではより攻撃的になり、すべての管理されていないcronジョブを解除します。その動作が本当に求めているものか確認してください。解除するリソースを気をつけるために`noop => true`をセットしたくなるかもしれません。
> Previously, using resources `{'cron': purge => true}` to purge cron resources would only purge jobs belonging to the current user performing the Puppet run (usually root). [In Puppet 4](http://docs.puppetlabs.com/puppet/4.0/reference/release_notes.html), this action is more aggressive and causes all unmanaged cron jobs to be purged.
>
> Make sure this is what you want. You might want to set `noop => true` on the purge resource to keep an eye on it.

# 型をチェックしてください
- `Check Your Data Types`

[型](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data.html)にはいくつか変更があります。
> [Data types](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data.html) have changed in a few ways.


## ブーリアンは常に本当のブーリアン
- `Boolean Facts are Always Real Booleans`

Puppet3では、ブーリアン（true/false値）は、`stringify_facts`設定を無効にしない限り文字列へ変換されていました。これは`if $is_virtual == 'true' {...}`のような比較が一般的であったことを示します。

Puppet4では、ブーリアンは決して文字列には変換されませんし、また先ほどの`==`演算子による比較は常にfalseになります。よって深刻な問題を引き起こすことがありえます。マニフェストの全てのブーリアンを文字列として扱っている比較について確認を行ってください。もしマニフェストをPuppet3/Puppet4の両方で動くようにしたければ、ブーリアンから文字列へ変換し、標準ライブラリの関数である`str2bool`を呼び出して変換することで変換できます。

> In Puppet 3, facts with boolean true/false values (like `$is_virtual`) were converted to strings unless the stringify_facts setting was disabled. This meant it was common to test for these facts with the == operator, like `if $is_virtual == 'true' { ... }`.

> In Puppet 4, boolean facts are never turned into strings, and those == comparisons will always evaluate to false. This can cause serious problems. Check your manifests for any comparisons that treat boolean facts like strings; if you need a manifest to work with both Puppet 3 and Puppet 4, you can convert a boolean to a string and then pass it to the stdlib module’s str2bool function:

> ```puppet
if str2bool("$is_virtual") { ... }
```

# DSLにおいて数値と文字列は別物
- Numbers and Strings Are Different in the DSL

より詳しい詳細については[こちらで。](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_number.html)

以前Puppetは全てを文字列へ変換しようとし、数的文脈で使われている時には文字列を数値へ変換し戻していました。Puppet4においては、DSL中の数値はパースされ内部的に数値として保持されます。次の例の２つの変数は、Puppet3においては同じでしたが、Puppet4においては異なるものになります。

```puppet
$port_a = 80   # 数としてパース・保持され、もし数値でなかった場合はエラーになる
$port_b = '80' # 文字としてパース・保持される
```

現在この違いは、厳密に数値が強制され、もし値が有効な数字から始まらなければエラーになります。

```puppet
node 1name {} # 1nameは有効な10進数ではないので無効です。この名前はquoteする必要が有ります
notice(0xggg) # 0xgggは有効な16進数ではないので無効です。
$a = 1 + 0789 # 0789は有効な8進数ではないので無効です。
```

> For full details, [see the language page about numeric values.](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_number.html)
> Previously, Puppet would convert everything to strings, then attempt to convert those strings back into numbers when they were used in a numeric context. In Puppet 4, numbers in the DSL are parsed and maintained internally as numbers. The following examples would have been equivalent in Puppet 3, but are now different:

> ```puppet
$port_a = 80   # Parsed and maintained as a number, errors if NOT a number
$port_b = '80' # Parsed and maintained as a string
```

> The difference now is that Puppet will STRICTLY enforce numerics and will throw errors if values that begin with a number are not valid numbers.

> ```puppet
node 1name {} # invalid because 1name is not a valid decimal number; you would need to quote this name
notice(0xggg) # invalid because 0xggg is not a valid hexadecimal number
$a = 1 + 0789 # invalid because 0789 is not a valid octal number
```

## 計算式
- Arithmetic Expressions

数式は文字列から数値へ変換されます。もし値が0もしくは0xから始まるとき、それらは８進数もしくは１６進数としてそれぞれ扱われます。もし計算式の両方が数値・数値へ変換できる文字列でない場合は、エラーが起こります。

```puppet
$valid = 40 + 50       # 両方とも数値なので有効です。
$valid = 25 + '30'     # '30'という文字列は数値へ変換できるので有効です。
$invalid = 40 + 0789   # 0789という値は有効な8進数でないので無効です。
$invalid = 40 + '0789' # '0789'という文字列は数値へ変換できないので無効です。
```

> Mathematical expressions still convert strings to numeric values. If a value begins with 0 or 0x, it will be interpreted as an octal or hex number, respectively. An error is raised if either side in an arithmetic expression is not a number or a string that can be converted to a number. For example:

> ```puppet
$valid = 40 + 50       # valid because both values are numeric
$valid = 25 + '30'     # valid because '30' can be cast numerically
$invalid = 40 + 0789   # invalid because 0789 isn't a valid octal number
$invalid = 40 + '0789' # invalid because '0789' can't be cast numerically
```

# 比較を確認する
- Check Your Comparisons

いくつかの比較演算子がPuppet4において変更されています。詳しくは[式と演算子](http://docs.puppetlabs.com/puppet/4.2/reference/lang_expressions.html)で。

> Some comparison operations have changed in Puppet 4. Read about [expressions and operators](http://docs.puppetlabs.com/puppet/4.2/reference/lang_expressions.html) for the full details.

## 文字列以外への正規表現
- Regular Expressions Against Non-Strings

文字列以外への正規表現マッチ処理はエラーになります。Puppet3系だと文字列以外の型もマッチ処理を行う前に文字列へ変換していました。（予測不能で未定義の結果も頻繁に）

```puppet
$securitylevel = 2

case $securitylevel {
  /[1-3]/: { notify { 'security low': } }
  /[4-7]/: { notify { 'security medium': } }
  default: { notify { 'security high': } }
}
```

Puppet4以前では、最初の正規表現はマッチするのでカタログに`{ 'security low': }`が通知されます。

Puppet4では、`$securityLevel`の値が文字列ではなく整数であるため全ての正規表現がマッチしません。その結果デフォルト条件がマッチし、`{ 'security high': }`が通知されることになります。

> Matching a value that is not a string with a regular expression now raises an error. In 3.x, other data types were converted to string form before matching (often with surprising and undefined results).

> ```puppet
$securitylevel = 2
>
case $securitylevel {
  /[1-3]/: { notify { 'security low': } }
  /[4-7]/: { notify { 'security medium': } }
  default: { notify { 'security high': } }
}
```

> Prior to Puppet 4.0, the first regex would match, and the notify `{ ‘security low’: }` resource would be put into the catalog.

> Now, in Puppet 4.0, neither of the regexes would match because the value of `$securitylevel` is an integer, not a string, and so the default condition would match, resulting in the inclusion of notify `{ 'security high': }` in the catalog.

## ブーリアンのコンテキストにおいて、空文字列は`true`である
- Empty Strings in Boolean Context are `true`

以前のバージョンのPuppetでは、空文字列はfalseとして評価されました。変数の値を渡したもしくは空のままの場合をチェックする条件比較において、変数やパラメータのデフォルト値として使われているのを目にしたことがあると思います。

```puppet
class empty_string_defaults (
  $parameter_to_check = ''
) {
  if $parameter_to_check {
    $parameter_to_check_real = $parameter_to_check
  } else {
    $parameter_to_check_real = 'default value'
  }
}
```

古いPuppetでは空文字列では`false`として評価されたので、シンプルなif文でデフォルト値を設定することができました。Puppet4においてこの振る舞いは`$parameter_to_check_real`によって変えることができます。

既存のコードベースについてこの振る舞いをチェックすることが可能です。[puppet-lint plugin](https://github.com/puppet-community/puppet-lint-empty_string-check)を参照ください。

また[ブーリアンについてのドキュメント](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_boolean.html)も参照してください。

> In previous versions of Puppet, an empty string was evaluated as a false boolean value. You would see this in variable and parameter default values where conditional checks would be used to determine if someone passed in a value or left it blank.

> ```puppet
class empty_string_defaults (
  $parameter_to_check = ''
) {
  if $parameter_to_check {
    $parameter_to_check_real = $parameter_to_check
  } else {
    $parameter_to_check_real = 'default value'
  }
}
```

> Puppet’s old behavior of evaluating the empty string as `false` would allow you to set the default based on a simple if-statement. In Puppet 4.x, this behavior is flipped and `$parameter_to_check_real` will be set to an empty string.

> You can check your existing codebase for this behavior with a [puppet-lint plugin](https://github.com/puppet-community/puppet-lint-empty_string-check).

> See [the language page on boolean values](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_boolean.html) for more info.

## `in`演算子は少しだけ異なる
- The `in` Operator Is Slightly Different

`in`演算子はかつては文字列比較において大文字・小文字を別のものとしてみなしていました。これは`==`演算子と異なります。Puppet4においては`==`演算子と同じように、大文字・小文字の区別を行いません。また以前は不可能だった正規表現と型の比較が可能です。

全体の詳細については[ドキュメントにおける定義](http://docs.puppetlabs.com/puppet/4.2/reference/lang_expressions.html#in)を参照してください。

> The `in` operator used to be case-sensitive when testing strings, which was inconsistent with the `==` operator. Now it’s case-insensitive, like `==`. It can also test regular expressions and data types, which wasn’t possible before.

> The full behavior is [defined in the documentation](http://docs.puppetlabs.com/puppet/4.2/reference/lang_expressions.html#in).

## 型の比較
- Comparing Data Types

異なる型は同じ型でない限り比較することはできません。数値と文字列の比較時に、わかりやすい変化として気づくでしょう。

> Different [data types](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data.html) can’t be compared as if they’re the same data type anymore. This is most noticeable when comparing numbers to strings.

# 二重バックスラッシュがある、シングルクオート表記の文字列を確認する
- Check Single-Quoted Strings for Double Backslashes

`\\`エスケープはシングルクオート表記において適切に動くようになります。以前はバックスラッシュを含む文字列はシングルクオート表記で扱うことはできませんでした。

リテラルとして二重バックスラッシュを含むことを想定している文字列は全て変更されるでしょう。リテラルとしての二重バックスラッシュは四重のバックスラッシュ`\\\\`に変更する必要があります。この振る舞いについては[文字列についてのドキュメント](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_string.html#single-quoted-strings)を参照してください。

> The `\\` escape now works properly in single-quoted strings. Previously, there was no way to end a single-quoted string with a backslash.

> This will change any existing strings that are supposed to have literal double backslashes in them; you’ll need to change them to quadruple backslashes. Read more about this behavior in [the language page about strings](http://docs.puppetlabs.com/puppet/4.2/reference/lang_data_string.html#single-quoted-strings).

# 変数・クラス・関数・Defined Type・その他の命名をチェックする
- Check Names of Variables, Classes, Functions, Defined Types, etc.

命名規則がより厳格に変更されました。

- クオート無しの大文字の単語は禁止されました
- 変数は大文字で始まってはいけません
- クラス・defined type・関数は、ハイフンを含んでも数字で始まってもいけません

> Naming conventions have changed and become more strict.

> - Capitalized bare words as un-quoted strings are no longer allowed.
> - Variables must not start with capital letters.
> - Classes, defined types, functions must not include hyphens or begin with digits.

# 無意味な式を確認する
- Check for Non-Productive Expressions

Puppet4のバリデーションロジックはエラーになるような式について何も効果もフラグも持ちません。

無意味な式の例を示すと、

```puppet
if true { } # 無意味です
$a = 10
```

もし式が未定義値を生み出す場合、それらは捨て去られます。注意すべきことは、マニフェスト・コードブロックの末尾、もしくはシーケンスの値については無意味な式として扱うことは決してありまえん。

もしPuppetが無意味なコードに対するエラーを発生させたら、コードの振る舞いに対して何も影響を与えない問題のコードを除去すべきです。

> Puppet 4.0.0 validates logic that has no effect and flags such expressions as being errors.

> An example of a non productive expression is:

> ```puppet
if true { } # non productive
$a = 10
```

> The if expression produces a value of undef, which is then thrown away. Note that expressions are never considered non-productive when they are the last in a manifest or block of code, as that is also the value of the sequence.

> If Puppet raises a non-productive expression error about your code, you should be able to remove the offending statements without changing the code’s behavior.

# 予約済みの単語になっているかもしれないことを確認する
- Check for Bare Words That May Now Be Reserved

Puppet4においては予約語が追加されています。マニフェストをチェックしクオートしていない文字列が[予約語リスト](http://docs.puppetlabs.com/puppet/4.2/reference/lang_reserved.html)を含んでいないかチェックし、必要であればクオートしてください。

> More reserved words were added in Puppet 4.0, so check your manifests for any un-quoted strings on [the reserved words list](http://docs.puppetlabs.com/puppet/4.2/reference/lang_reserved.html) and quote them as needed.

# ハッシュや配列にアクセスするときの余分な空白文字を確認する
- Check for Excess Spaces When Accessing Hashes and Arrays

値中や角括弧の左の空白文字は重要です。Puppetは空白文字があるかどうかで異なる結果を出力します。

悪い例

```puppet
$a [3]  # 最初は変数aの値になり、次は一つの値を含む配列のリテラル表記
```

良い例

```puppet
$a[3]   # 配列aの3番目の値を参照します
```

> The space between a value and a left bracket is significant, and Puppet will output different results if there is a space.

> Bad:

> ```puppet
$a [3]  # first the value of a, then a literal array with the single value 3 in it
```

> Good:

> ```puppet
$a[3]   # index 3 in the array referenced by $a
```

# 括弧無しの関数呼び出しを確認する
- Check for Function Calls Without Parentheses

ある限られた関数だけが括弧無しに呼び出し可能です。[関数についてのドキュメント](http://docs.puppetlabs.com/puppet/4.2/reference/lang_functions.html)を参照してください。

> Only certain functions are allowed to be called without parentheses. Read [the documentation on functions](http://docs.puppetlabs.com/puppet/4.2/reference/lang_functions.html) to learn when parentheses can be omitted.

# 正規表現の正しいシンタックスを確認する
- Check Your Regular Expressions for Correct Syntax

Puppet4はRuby2のコピーを独自にバンドルしており、正規表現シンタックスは以前のPuppetで実行していたRuby1.8.7とは少しだけ異なるものになります。2つのRubyはそれぞれ異なる正規表現エンジンを使っているため異なる結果になっています。

> Puppet 4 bundles its own copy of Ruby 2.x, and the regex syntax is slightly different than Ruby 1.8.7, which you may have been running prior to upgrade. Because the two versions of Ruby use differing regex engines, your results may vary.

# Hieraで使うYAMLファイルが正しいシンタックスかどうか確認する
- Check YAML Files Used by Hiera, etc. for Correct Syntax

もしRubyのバージョンがアップグレードされたら、YAMLのパーサーがより厳格になるかもしれません。文字列が含んでいる`%`がクオートされていることを確認してください。

> If the Ruby version changed since upgrade, the YAML parser will be more strict. Ensure strings containing a `%` are quoted.

# 全てのファイルのモード属性を確認する
- Check the mode Attribute of Any File Resources

ファイルリソースのモード属性が文字列であることを確認してください。もし8進数を使っていたら、それらは10進数へ変換されるでしょう。そして`chown`コマンドを実行するさいに誤った数値として文字列で表現されます。

> [The mode attribute](http://docs.puppetlabs.com/references/4.2.latest/type.html#file-attribute-mode) of a file resource must be a string. If you use an actual octal number, it will be converted to a decimal number, then converted back to a string representing the wrong number when it comes time to run the `chown` command.

# リフレッシュイベントを受け取る`noop => true`が設定されているリソースを確認する
- Check for Resources with `noop => true` that Receive Refresh Events

Puppet3においては、`noop`をtrueにすることでno-opモードを退避することができ、リフレッシュイベント（`notify`もしくは`subscribe`メタパラメータ、`~>`矢印）を受け取ったら何かしらの変化を発生させることができました。

Puppet4ではこれらは不可能になり、no-opリソースは常にno-opであり続けます。多くのユーザーにとっては何も不都合な点はないでしょうが、ほんのわずかな可能性として設定がこの振る舞いに依存していないか、確認してください。

> In Puppet 3, resources with `noop` set to true could escape no-op mode and cause changes if they received a refresh event (via the `notify` or `subscribe` metaparameters or the `~>` arrow).

> This is no longer possible in Puppet 4; no-op resources always stay no-op. For most users that’s a win with no downside, but there’s a slim chance that your configurations relied on this behavior, so look around to make sure.

# 削除された機能を確認する
- Check for Removed Features

Puppet4においていくつか削除された機能があります。それらは、もしくはより良い回避方法があります。

> Several things were removed from Puppet 4, either because they no longer had practical use cases and were not being used, or there was a better work around.

## `import`文とノード継承
- `import` Statements and Node Inheritance

`import`が削除されたので、メインマニフェストをディレクトリとして再作成する必要があります。詳しくは[メインマニフェストのドキュメント](http://docs.puppetlabs.com/puppet/4.2/reference/dirs_manifest.html)を読んでください。

ノード継承も同様に削除されました。もはやノードの定義を別のノードの定義から継承することはできません。Hieraとラッパーモジュールを使ってシステム設定を構築することで、より良い結果を得られます。

> Removal of `import` means you’ll have to use a directory as your main manifest to recreate this functionality. Read [the Main Manifest page](http://docs.puppetlabs.com/puppet/4.2/reference/dirs_manifest.html) to learn more about this method.

> Node inheritance has also been removed. It is no longer possible to have node definitions that inherit from another node definition. You can get better results by using a combination of Hiera data and wrapper modules to construct system configurations.

参考
[Qiita: Puppet 4.x から消えた import の代わりに Main Manifest を Directory に変更する](http://qiita.com/hfm/items/a1c39a4e07d4f786d52f)

## ERBにおける動的スコープ
- Dynamic Scoping in ERB

Puppet4.0において、ERBテンプレートにおける変数の動的スコープは削除されています。

```puppet
class outer {
  $var = 'dynamic'
  include inner
}
>
class inner {
  notice(inline_template('<%= @var %>'))
}
>
include outer
```

以前のPuppetでは、`notice()`へ渡されている値は解決され、動的に作られた文字列を得ます。
現在のPuppet4では、`notice()`へ渡されている値は空文字として解決されます。
リソースデフォルトに対する振る舞いは変更されていません。

> In Puppet 4.0, dynamic scoping has been removed for variables in ERB templates.

> ```puppet
class outer {
  $var = 'dynamic'
  include inner
}
>
class inner {
  notice(inline_template('<%= @var %>'))
}
>
include outer
```

> Prior to Puppet 4.x, the value supplied to notice() will resolve to the string dynamic.

> Now, in Puppet 4.x, the value supplied to notice() will resolve to an empty string.

> The behavior of resource defaults has not been changed.

## `+=`と`-=`
- += and -=

`+=`演算子と`-=`演算子は削除されました。puppet-lintプラグインで既存のコードベースを検査できます。

> These operators have been removed. You can run the puppet-lint plugin to check your existing code base for them.

## Ruby DSLを使用しているモジュール
- Modules Using the Ruby DSL

ついに長らく非推奨だったRuby DSLが完全に削除されました。

> Finally, the long-deprecated Ruby DSL has been fully removed from Puppet.