Ansible playbook 用于验证目录并在非空时检索服务器主机名或IP。

huangapple go评论103阅读模式
英文:

Ansible playbook to verify directory and retrieve server hostname or IP if not empty

问题

我想使用Ansible检查一个目录是否为空。
如果目录不为空,我想要获取服务器的主机名或IP地址。
有人可以帮助我吗?
谢谢!

我尝试进行了一个测试。

  1. - hosts: all
  2. tasks:
  3. - find :
  4. paths: /tmp/foo
  5. file_type: all
  6. hidden: true
  7. register: out
  8. - fail :
  9. msg: /tmp/foo目录不为空
  10. when: out.matched != 0
英文:

I want to check a directory with ansible if it's not empty.
I want to have the server hostname or IP address if the directory is not empty.
Can anyone help me?
Thanks!

I tried to make a test.

  1. - hosts: all
  2. tasks:
  3. - find :
  4. paths: /tmp/foo
  5. file_type: all
  6. hidden: true
  7. register: out
  8. - fail :
  9. msg: the /tmp/foo directory is not empty
  10. when: out.matched != 0

答案1

得分: 1

"Check a directory and list servers if empty."

答: 有两种非常有用的模式,你应该逐步了解并理解细节。

例如,给定两个远程主机,第二个主机上的目录是空的

  1. shell> ssh admin@test_11 find /tmp/test_dir
  2. /tmp/test_dir
  3. /tmp/test_dir/bar
  4. /tmp/test_dir/foo
  1. shell> ssh admin@test_13 find /tmp/test_dir
  2. /tmp/test_dir

查找文件

  1. - find:
  2. paths: /tmp/test_dir
  3. file_type: any
  4. hidden: true
  5. register: out
  1. 创建一个事实的字典
  1. report: "{{ dict(ansible_play_hosts|
  2. zip(ansible_play_hosts|
  3. map('extract', hostvars, ['out', 'matched']))) }}"

得到

  1. report:
  2. test_11: 2
  3. test_13: 0
  1. 从字典中选择/拒绝属性,并获取满足条件的属性的名称
  1. empty: "{{ report|dict2items|
  2. rejectattr('value')|
  3. map(attribute='key') }}"

得到你想要的结果

  1. empty:
  2. - test_13

完整的用于测试的示例playbook

  1. - hosts: all
  2. vars:
  3. report: "{{ dict(ansible_play_hosts|
  4. zip(ansible_play_hosts|
  5. map('extract', hostvars, ['out', 'matched']))) }}"
  6. empty: "{{ report|dict2items|
  7. rejectattr('value')|
  8. map(attribute='key') }}"
  9. tasks:
  10. - find:
  11. paths: /tmp/test_dir
  12. file_type: any
  13. hidden: true
  14. register: out
  15. - debug:
  16. var: report
  17. run_once: true
  18. - debug:
  19. var: empty
  20. run_once: true

英文:

Q: "Check a directory and list servers if empty."

A: There are two very useful patterns you should go step by step through and understand the details.

For example, given two remote hosts, the directory is empty on the second one

  1. shell> ssh admin@test_11 find /tmp/test_dir
  2. /tmp/test_dir
  3. /tmp/test_dir/bar
  4. /tmp/test_dir/foo
  1. shell> ssh admin@test_13 find /tmp/test_dir
  2. /tmp/test_dir

Find the files

  1. - find:
  2. paths: /tmp/test_dir
  3. file_type: any
  4. hidden: true
  5. register: out
  1. Crete a dictionary of the facts
  1. report: "{{ dict(ansible_play_hosts|
  2. zip(ansible_play_hosts|
  3. map('extract', hostvars, ['out', 'matched']))) }}"

gives

  1. report:
  2. test_11: 2
  3. test_13: 0
  1. Select/reject attributes from a dictionary and get the names of the attributes that match the condition
  1. empty: "{{ report|dict2items|
  2. rejectattr('value')|
  3. map(attribute='key') }}"

gives what you want

  1. empty:
  2. - test_13

<hr>

<sup>

Example of a complete playbook for testing

  1. - hosts: all
  2. vars:
  3. report: &quot;{{ dict(ansible_play_hosts|
  4. zip(ansible_play_hosts|
  5. map(&#39;extract&#39;, hostvars, [&#39;out&#39;, &#39;matched&#39;]))) }}&quot;
  6. empty: &quot;{{ report|dict2items|
  7. rejectattr(&#39;value&#39;)|
  8. map(attribute=&#39;key&#39;) }}&quot;
  9. tasks:
  10. - find:
  11. paths: /tmp/test_dir
  12. file_type: any
  13. hidden: true
  14. register: out
  15. - debug:
  16. var: report
  17. run_once: true
  18. - debug:
  19. var: empty
  20. run_once: true

</sup>

答案2

得分: 0

> 我想用Ansible检查一个目录是否为空。

既然未定义“空”是什么意思,以及是否可能存在零字节文件,我理解你的问题是你对文件夹大小感兴趣。

根据在条件中使用文件夹大小的内容,stat 模块返回的 size 属性 不会 告诉你文件夹内容的大小!它只报告目录条目的大小,这可能取决于诸如目录中包含的文件数量等多种因素。

如果你想计算目录中包含的数据量,你可以进一步参考这里的回答Ansible:需要查找文件夹/目录或文件的通用解决方案

由于这需要使用 commandshell,这在一般情况下不被推荐,可能可以将任务转换为自定义模块。为此,创建一个用 Bash 或 Shell 编写的自定义模块似乎是最好的方法。

以下是一个概念/示例模块,它接受一个字符串参数(path),并测试它是目录还是文件。然后提供目录及其所有文件(包括子目录)的大小,或仅文件大小作为结果集。

概念/示例模块 size.sh

  1. #!/bin/sh
  2. exec 3&gt;&amp;1 4&gt;&amp;2 &gt; /dev/null 2&gt;&amp;1
  3. # 创建函数
  4. function return_json() {
  5. exec 1&gt;&amp;3 2&gt;&amp;4
  6. jq --null-input --monochrome-output \
  7. --arg changed &quot;$changed&quot; \
  8. --arg rc &quot;$rc&quot; \
  9. --arg stdout &quot;$stdout&quot; \
  10. --arg stderr &quot;$stderr&quot; \
  11. --arg directory &quot;$directory&quot; \
  12. --arg file &quot;$file&quot; \
  13. --arg msg &quot;$msg&quot; \
  14. &#39;$ARGS.named&#39;
  15. exec 3&gt;&amp;1 4&gt;&amp;2 &gt; /dev/null 2&gt;&amp;1
  16. }
  17. # 模块辅助函数
  18. function dirsize() {
  19. du -sh &quot;$path&quot; | sort -h
  20. }
  21. function filesize() {
  22. du -sh &quot;$path&quot;
  23. }
  24. # 模块主要逻辑
  25. function module_logic() {
  26. if [ -f &quot;$path&quot; ]; then
  27. filesize $path
  28. file=&quot;true&quot;
  29. elif [ -d &quot;$path&quot; ]; then
  30. dirsize $path
  31. directory=&quot;true&quot;
  32. else
  33. stderr=&quot;无法访问:文件或目录不存在或权限被拒绝。&quot;
  34. rc=1
  35. fi
  36. }
  37. # 设置默认值
  38. changed=&quot;false&quot;
  39. rc=0
  40. stdout=&quot;&quot;
  41. stderr=&quot;&quot;
  42. directory=&quot;false&quot;
  43. file=&quot;false&quot;
  44. msg=&quot;&quot;
  45. source &quot;$1&quot;
  46. # 检查先决条件
  47. if ! which jq &amp;&gt;/dev/null; then
  48. exec 1&gt;&amp;3 2&gt;&amp;4
  49. printf &quot;{ \&quot;changed\&quot;: \&quot;$changed\&quot;,
  50. \&quot;rc\&quot;: \&quot;1\&quot; ,
  51. \&quot;stdout\&quot;: \&quot;\&quot;,
  52. \&quot;stderr\&quot;: \&quot;找不到命令:此模块需要在目标主机上安装 'jq'。正在退出... \&quot;,
  53. \&quot;directory\&quot;: \&quot;false\&quot; ,
  54. \&quot;file\&quot;: \&quot;false\&quot;,
  55. \&quot;msg\&quot;: \&quot;\&quot;}&quot;
  56. exit 127
  57. fi
  58. if ! grep -q &quot;Red Hat Enterprise Linux&quot; /etc/redhat-release; then
  59. stderr=&quot;不支持此操作:未找到 Red Hat Enterprise Linux。正在退出...&quot;
  60. rc=95
  61. return_json
  62. exit $rc
  63. fi
  64. # 验证参数键和值
  65. if [ -z &quot;$path&quot; ]; then
  66. stderr=&quot;无效参数:未提供参数路径。正在退出...&quot;
  67. rc=22
  68. return_json
  69. exit $rc
  70. fi
  71. if [[ $path == *[&#39;!:*&#39;]* ]]; then
  72. stderr=&quot;无效参数:值路径包含无效字符。正在退出...&quot;
  73. rc=22
  74. return_json
  75. exit $rc
  76. fi
  77. if [ ${#path} -ge 127 ]; then
  78. stderr=&quot;参数太长:值路径字符太多。正在退出...&quot;
  79. rc=7
  80. return_json
  81. exit $rc
  82. fi
  83. # 主要
  84. module_logic $path
  85. changed=&quot;false&quot;
  86. msg=$(module_logic $path | sed &#39;s/\t/ /g&#39;)
  87. return_json
  88. exit $rc

测试Playbook size.yml

  1. ---
  2. - hosts: test
  3. become: false
  4. gather_facts: false
  5. tasks:
  6. - name: 获取路径后面的大小
  7. size:
  8. path: /root/anaconda-ks.cfg
  9. register: result
  10. ignore_errors: true
  11. - name: 获取路径后面的大小
  12. size:
  13. path: &#39;&#39;
  14. register: result
  15. ignore_errors: true
  16. - name: 获取路径后面的大小
  17. size:
  18. register: result
  19. ignore_errors: true
  20. - name: 获取路径后面的大小
  21. size:
  22. path: &quot;/home/{{ ansible_user }}/*&quot;
  23. register: result
  24. ignore_errors: true
  25. - name: 获取路径后面的大小
  26. size:
  27. path: &quot;/home/{{ ansible_user }}/1111111111/2222222222/3333333333/4444444444/5555555555/6666666666/
  28. <details>
  29. <summary>英文:</summary>
  30. &gt; _I want to check a directory with Ansible if it&#39;s not empty._
  31. Since it is not defined what empty means and if there could be [zero byte files](https://stackoverflow.com/a/4955006/6771046), I understand your question that you are interested in the folder size.
  32. According [Use folder size in Conditional](https://stackoverflow.com/a/59910613/6771046)
  33. &gt; _The size attribute returned by the stat module for a folder does **not** tell you the size of the folder&#39;s contents! It only reports the size of the directory entry, which may depend on a number of factors such as the number of files contained in the directory._
  34. If you&#39;re looking to calculate the amount of data contained in a folder, you may [proceed further with the answer there](https://stackoverflow.com/a/59910613/6771046) or [Ansible: Need generic solution to find size of folder/directory or file](https://stackoverflow.com/a/73687567/6771046).
  35. Since that require to use `command` or `shell` which is not generally recommended for all cases, it might be possible to transfer the task into a Custom Module. To do so, creating a Custom Module written in Bash or Shell seems to be the best approach.
  36. The following concept / example module takes a string parameter (`path`) and test if it is a directory or file. After it is providing the size of the directory with all files and including sub directories or the file size only as results set.
  37. **Concept / Example Module** `size.sh`
  38. ```sh
  39. #!/bin/sh
  40. exec 3&gt;&amp;1 4&gt;&amp;2 &gt; /dev/null 2&gt;&amp;1
  41. # Create functions
  42. function return_json() {
  43. exec 1&gt;&amp;3 2&gt;&amp;4
  44. jq --null-input --monochrome-output \
  45. --arg changed &quot;$changed&quot; \
  46. --arg rc &quot;$rc&quot; \
  47. --arg stdout &quot;$stdout&quot; \
  48. --arg stderr &quot;$stderr&quot; \
  49. --arg directory &quot;$directory&quot; \
  50. --arg file &quot;$file&quot; \
  51. --arg msg &quot;$msg&quot; \
  52. &#39;$ARGS.named&#39;
  53. exec 3&gt;&amp;1 4&gt;&amp;2 &gt; /dev/null 2&gt;&amp;1
  54. }
  55. # Module helper functions
  56. function dirsize() {
  57. du -sh &quot;$path&quot; | sort -h
  58. }
  59. function filesize() {
  60. du -sh &quot;$path&quot;
  61. }
  62. # Module main logic
  63. function module_logic() {
  64. if [ -f &quot;$path&quot; ]; then
  65. filesize $path
  66. file=&quot;true&quot;
  67. elif [ -d &quot;$path&quot; ]; then
  68. dirsize $path
  69. directory=&quot;true&quot;
  70. else
  71. stderr=&quot;Cannot access: No such file or directory or Permission denied.&quot;
  72. rc=1
  73. fi
  74. }
  75. # Set default values
  76. changed=&quot;false&quot;
  77. rc=0
  78. stdout=&quot;&quot;
  79. stderr=&quot;&quot;
  80. directory=&quot;false&quot;
  81. file=&quot;false&quot;
  82. msg=&quot;&quot;
  83. source &quot;$1&quot;
  84. # Check prerequisites
  85. if ! which jq &amp;&gt;/dev/null; then
  86. exec 1&gt;&amp;3 2&gt;&amp;4
  87. printf &quot;{ \&quot;changed\&quot;: \&quot;$changed\&quot;,
  88. \&quot;rc\&quot;: \&quot;1\&quot; ,
  89. \&quot;stdout\&quot;: \&quot;\&quot;,
  90. \&quot;stderr\&quot;: \&quot;Command not found: This module require &#39;jq&#39; installed on the target host. Exiting ...\&quot;,
  91. \&quot;directory\&quot;: \&quot;false\&quot; ,
  92. \&quot;file\&quot;: \&quot;false\&quot;,
  93. \&quot;msg\&quot;: \&quot;\&quot;}&quot;
  94. exit 127
  95. fi
  96. if ! grep -q &quot;Red Hat Enterprise Linux&quot; /etc/redhat-release; then
  97. stderr=&quot;Operation not supported: Red Hat Enterprise Linux not found. Exiting ...&quot;
  98. rc=95
  99. return_json
  100. exit $rc
  101. fi
  102. # Validate parameter key and value
  103. if [ -z &quot;$path&quot; ]; then
  104. stderr=&quot;Invalid argument: Parameter path is not provided. Exiting ...&quot;
  105. rc=22
  106. return_json
  107. exit $rc
  108. fi
  109. if [[ $path == *[&#39;!:*&#39;]* ]]; then
  110. stderr=&quot;Invalid argument: Value path contains invalid characters. Exiting ...&quot;
  111. rc=22
  112. return_json
  113. exit $rc
  114. fi
  115. if [ ${#path} -ge 127 ]; then
  116. stderr=&quot;Argument too long: Value path has too many characters. Exiting ...&quot;
  117. rc=7
  118. return_json
  119. exit $rc
  120. fi
  121. # Main
  122. module_logic $path
  123. changed=&quot;false&quot;
  124. msg=$(module_logic $path | sed &#39;s/\t/ /g&#39;)
  125. return_json
  126. exit $rc

Test Playbook size.yml

  1. ---
  2. - hosts: test
  3. become: false
  4. gather_facts: false
  5. tasks:
  6. - name: Get size behind path
  7. size:
  8. path: /root/anaconda-ks.cfg
  9. register: result
  10. ignore_errors: true
  11. - name: Get size behind path
  12. size:
  13. path: &#39;&#39;
  14. register: result
  15. ignore_errors: true
  16. - name: Get size behind path
  17. size:
  18. register: result
  19. ignore_errors: true
  20. - name: Get size behind path
  21. size:
  22. path: &quot;/home/{{ ansible_user }}/*&quot;
  23. register: result
  24. ignore_errors: true
  25. - name: Get size behind path
  26. size:
  27. path: &quot;/home/{{ ansible_user }}/1111111111/2222222222/3333333333/4444444444/5555555555/6666666666/7777777777/8888888888/9999999999/0000000000/aaaaaaaaaa/bbbbbbbbbb/cccccccccc/&quot;
  28. register: result
  29. ignore_errors: true
  30. - name: Get size behind path
  31. size:
  32. path: /home/{{ ansible_user }}
  33. register: result
  34. - name: Show result
  35. debug:
  36. var: result

Result ansible-playbook --user ${ANSIBLE_USER} size.yml

  1. TASK [Get size behind path] **********************************************
  2. fatal: [test.example.com]: FAILED! =&gt; changed=false
  3. msg: &#39;&#39;
  4. rc: &#39;1&#39;
  5. stderr: &#39;Cannot access: No such file or directory or Permission denied.&#39;
  6. stderr_lines: &lt;omitted&gt;
  7. stdout: &#39;&#39;
  8. stdout_lines: &lt;omitted&gt;
  9. ...ignoring
  10. TASK [Get size behind path] **********************************************
  11. fatal: [test.example.com]: FAILED! =&gt; changed=false
  12. msg: &#39;&#39;
  13. rc: &#39;1&#39;
  14. stderr: Parameter path is not provided. Exiting ...
  15. stderr_lines: &lt;omitted&gt;
  16. stdout: &#39;&#39;
  17. stdout_lines: &lt;omitted&gt;
  18. ...ignoring
  19. TASK [Get size behind path] **********************************************
  20. fatal: [test.example.com]: FAILED! =&gt; changed=false
  21. directory: &#39;false&#39;
  22. file: &#39;false&#39;
  23. msg: &#39;&#39;
  24. rc: &#39;22&#39;
  25. stderr: &#39;Invalid argument: Value path contains invalid characters. Exiting ...&#39;
  26. stderr_lines: &lt;omitted&gt;
  27. stdout: &#39;&#39;
  28. stdout_lines: &lt;omitted&gt;
  29. ...ignoring
  30. TASK [Get size behind path] **********************************************
  31. fatal: [test.example.com]: FAILED! =&gt; changed=false
  32. msg: &#39;&#39;
  33. rc: &#39;7&#39;
  34. stderr: Argument &#39;path&#39; too long. Exiting ...
  35. stderr_lines: &lt;omitted&gt;
  36. stdout: &#39;&#39;
  37. stdout_lines: &lt;omitted&gt;
  38. ...ignoring
  39. TASK [Get size behind path] **********************************************
  40. changed: [test.example.com]
  41. TASK [Show result] *******************************************************
  42. ok: [test.example.com] =&gt;
  43. result:
  44. changed: &#39;false&#39;
  45. failed: false
  46. msg: 722M /home/user
  47. rc: &#39;0&#39;
  48. stderr: &#39;&#39;
  49. stderr_lines: []
  50. stdout: &#39;&#39;
  51. stdout_lines: []

Thanks to

For script and module

For general Linux and Shell

huangapple
  • 本文由 发表于 2023年6月1日 16:05:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379857.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定