yamlエラー - 誤ったエスケープが原因である可能性がありますが、問題を識別できません。

yamlエラー - 誤ったエスケープが原因である可能性がありますが、問題を識別できません。

次の行はエラー(... request body malformed."})を発生させます。これはuser-data.ymlの一部であり、作成時にサーバーをブートストラップするためにDigital Ocean APIの一部としてcloud-initと共に使用されます。

sed -ie '\$a\ \n\#Add logfile information\nlogfile /var/log/ntp.log' /etc/ntp.conf

デフォルトでは、次のことを行う必要があります。

  • 空行を追加
  • 次の行にコメントを追加
  • 次の行に文字列を追加する

はい読み込み中 それ userdata.yml カーニバルからスクリプトは次のとおりです。

curl -X POST "https://api.digitalocean.com/v2/droplets" \
-d'{"name":"'$droplet_name'",
"region": "'$region'",
"size": "'$size'",
"image": "'$image'",
"backups":false,
"ipv6":false,
"private_networking":false,
"user_data":
"'"$(cat /user-data.yaml)"'",
  "ssh_keys": '$root_ssh_pub_key'}' \
  -H "Authorization: Bearer $api_key" \
  -H "Content-Type: application/json"

数時間ハッキングした後は、コード盲になることもあります。

答え1

あなたのsedは私のシステムに「終了していない正規表現」を提供します。次の操作を実行できます。

echo abc > xy
sed -ie '$a\\n#Add logfile information\nlogfile /var/log/ntp.log' xy
cat xy

これは作る:

abc

#Add logfile information
logfile /var/log/ntp.log

YAMLアップロードについては、これが追加する内容に影響を与えるかどうかはわかりません。アップロードされたデータを調べることができない場合は、拡張YAMLをファイルaに作成し、カールを使用してアップロードするxyz.yaml方法で作成することをお勧めします-d @xyz.yaml。これにより、アップロードしたコンテンツが期待した内容と正確に一致することを確認できます。

答え2

結局私は自分で直しました...

DO APIを使用して、次のチュートリアルに従う必要がありますか?これ(記事の中間を参照)次のいずれかのエラーが発生する可能性があります。

エラー1同様の問題が発生します...request body malformed。この問題を解決するには、yamlで文字列/文字をエスケープすることを忘れないでください。

エラー2一見すると問題はありません。 APIリクエストの実行が完了し、ドロップレットが回転し、特別なアクションを実行しない限りこれに気付かない可能性があります(スクリプトがシステムで実行するアクションを確認しないと...)。ただし、cloud-initのログを確認すると表示されますfailed loading yaml blob。これは、エスケープが必要な文字が十分に頻繁にエスケープされないためです(?!)。

例:

  • これにより、エラー1(エスケープドル文字の欠落)が発生します。
    sed -i -e '$a\ \n#Add logfile information\nlogfile /var/log/ntp.log' /etc/ntp.conf
  • これによりエラー2が発生します(ドルは巧妙にエスケープされていますが、ここでは1回のエスケープだけでは不十分です...)。
    sed -i -e '\$a\ \n#Add logfile information\nlogfile /var/log/ntp.log' /etc/ntp.conf

したがって、解決策は次のとおりです。
sed -i -e '\\$a\\ \\n#Add logfile information\\nlogfile /var/log/ntp.log' /etc/ntp.conf

実際に読んでいる人がいて、私がどれだけ挫折したかを理解する人がいる場合は、ここで何が起こっているのかを説明できるかどうかを教えてください。学ぶ。

私が理解できる唯一の理由は、baskスクリプトがyamlを取得し、リモートシェルを介してjsonに送信するときにさらに「注意」が必要なので、二重エスケープが必要なことです。 !

答え3

複数のキーと値を含むJSONドキュメントをアップロードしたいようです。ファイルは次のようになります。見苦しいたとえば、文字列にリテラル改行文字、二重引用符など、特定のJSONエンコーディングが必要な文字が含まれている場合など、値の1つが無効である場合

すべての値が正しくエンコードされるようにするには、JSON処理ツールの形式を使用すると便利です。jqまたはjo。さまざまな文字などをエスケープして手動でデータを準備するよりも、このようなツールを使用する方が良いでしょう。


使用jq:

jq -cn \
    --arg name "$droplet_name" \
    --arg size "$size" \
    --arg image "$image" \
    --argjson backups false \
    --argjson ipv6 false \
    --argjson private_networking false \
    --arg user_data "$(cat /user-data.yml)" \
    --arg ssh_keys "$root_ssh_pub_key" \
    '$ARGS.named'

デフォルトでは、--argすべての文字列だけでなく、--argjson文字列以外の値(数値とブール値)にも適用されます。

/user-data.yml大きな文書の場合は、jqコマンドラインから拡張するのではなく読み取ることができます。

jq -cn -Rs \
    --arg name "$droplet_name" \
    --arg size "$size" \
    --arg image "$image" \
    --argjson backups false \
    --argjson ipv6 false \
    --argjson private_networking false \
    --arg ssh_keys "$root_ssh_pub_key" \
    '$ARGS.named + { user_data: input }' /user-data.yml

これはファイルの最後の改行文字も保持します/use-data.yml


そしてjo

jo \
    name="$droplet_name" \
    size="$size" \
    image="$image" \
    backups=false \
    ipv6=false \
    private_networking=false \
    user_data=@/user-data.yml \
    ssh_keys="$root_ssh_pub_key"

ここでは、ユーザーデータファイルを読み取ってエンコードするために@letを使用しています。jo使用することもできましたが、use_data="$(cat ...)"より多くの入力が必要だったので、より短くて読みやすいバリエーションを選択しました。また、jo値の型が自動的に推論されるため、null空の文字列の代わりに欠落している値が得られます。


どのコマンドを使用しても、そのコマンドの出力を次に直接パイプできますcurl

json-generating-command |
curl --silent --show-error \
    --header "Authorization: Bearer $api_key" \
    --json @- 'some-URL-here'

関連情報