下面的行会导致错误 (... request body malformed."}
)。它是 user-data.yml 的一部分,与 cloud-init 一起使用,作为数字海洋 API 的一部分,在创建时引导服务器。
sed -ie '\$a\ \n\#Add logfile information\nlogfile /var/log/ntp.log' /etc/ntp.conf
基本上,它应该执行以下操作:
- 追加一个空行
- 在下一行添加注释
- 将字符串添加到下一行
我是加载中 那 用户数据.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 上传,我不确定这是否会影响您附加的内容。如果您无法检查上传的数据,我建议通过将其写入文件a来生成扩展的YAML xyz.yaml
,然后使用curl上传它-d @xyz.yaml
。这使您有机会确保上传的内容完全符合预期。
答案2
终于自己修好了...
您是否应该使用 DO API 并遵循一些教程,例如这(参考文章的中间)您很可能会遇到以下错误之一。
错误1导致类似的问题...request body malformed
要解决它,请确保您没有忘记转义 yaml 中的任何字符串/字符。
错误2第一眼看上去不会引发任何问题。你的 api 请求运行完毕,droplet 旋转起来,除非你没有做任何花哨的事情,否则你甚至可能不会注意到它(如果你不检查你的脚本对系统做了什么......)。但是,检查 cloud-init 的日志会显示它failed loading yaml blob
。这是因为需要转义的字符没有足够频繁地转义(?!)。
例子:
- 这将导致错误 1(错过转义美元字符):
sed -i -e '$a\ \n#Add logfile information\nlogfile /var/log/ntp.log' /etc/ntp.conf
- 这将导致错误 2(美元被巧妙地转义,但这里单次转义还不够......):
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 并通过远程 shell 以 json 形式发送时,它需要更多的“照顾”,因此需要双重转义?!
答案3
您似乎想要上传一个包含多个键和值的 JSON 文档。该文件将是畸形的如果任何值无效,例如,如果字符串包含需要特定 JSON 编码的字符,例如文字换行符和双引号等。
为了确保所有值都正确编码,如果您使用某种形式的 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"
在这里,我使用@
letjo
读取和编码用户数据文件。我本来可以使用use_data="$(cat ...)"
,但由于这样需要输入更多内容,所以我选择了更短、更易于阅读的变体。另请注意,它jo
会自动推断值的类型,因此您将得到null
缺失值,而不是空字符串。
无论您使用哪个命令,您都可以将该命令的输出直接传输到curl
:
json-generating-command |
curl --silent --show-error \
--header "Authorization: Bearer $api_key" \
--json @- 'some-URL-here'