Ansible XML 以幂等方式添加嵌套子项

Ansible XML Adding Nested Children Idempotently

提问人:shepster 提问时间:10/12/2023 最后编辑:β.εηοιτ.βεshepster 更新时间:10/14/2023 访问量:55

问:

我正在尝试修复 V-222934(Tomcat 默认 Servlet 参考中的其他信息)

从文件开始:web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                       http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- Much more in actual web.xml -->
</web-app>

我想以

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                       http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
          <param-name>readonly</param-name>
          <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- Much more in actual web.xml -->
</web-app>

我从以下 Ansible 开始:

    - name: "V-222934: DefaultServlet set to readonly for PUT and DELETE"
      community.general.xml:
        path: "{{ atl_product_installation_versioned }}/conf/web.xml"
        xpath: "/j:web-app/j:servlet/j:servlet-class[text()=\"org.apache.catalina.servlets.DefaultServlet\"]"
        insertafter: yes
        add_children:
          - init-param:
            - param-name: readonly
            - param-value: true
        pretty_print: yes
        namespaces:
          j: http://xmlns.jcp.org/xml/ns/javaee

但这引发了一个错误,抱怨列表而不是字节/unicode。

切换到我取得了一些成功:input_type: xml

    - name: "V-222934: DefaultServlet set to readonly for PUT and DELETE"
      community.general.xml:
        path: "{{ atl_product_installation_versioned }}/conf/web.xml"
        xpath: "/j:web-app/j:servlet/j:servlet-class[text()=\"org.apache.catalina.servlets.DefaultServlet\"]"
        insertafter: yes
        input_type: xml
        add_children:
          - "<init-param><param-name>readonly</param-name><param-value>true</param-value></init-param>"
        pretty_print: yes
        namespaces:
          j: http://xmlns.jcp.org/xml/ns/javaee

这有效但不是无力的。

我的大/主要问题是:我如何使这个幂等?

此外,在我的实际文件中,有不止一个.我可以接受的一个解决方案是指定.但是,我想以 .<servlet>/ns:servlet[1]<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>

我有一个小问题:如何让 yaml 输入类型工作?(我认为代码看起来更干净,并且使用这种格式更有意义。

最后:我对命名空间的了解只够让 Ansible 工作。如果有人有更干净/更清晰的代码编写方式,我愿意接受任何改进。

XML Ansible 命名空间 幂等

评论

0赞 jdweng 10/12/2023
您发布的大部分内容都无关紧要。您所要做的就是修改 XML 文件。您需要动态更改 XML 还是仅更改一次?如果只有一次,为什么要在代码中做?您尝试做的就是测试 xml 文件是否具有只读参数,如果没有该参数,请添加只读参数,这样您就不会多次插入它。
2赞 shepster 10/12/2023
Ansible 的整个想法不就是只做一次更改吗?是的,我想一次更正 XML,但这是在多个系统上完成的,我负担不起簿记来跟踪我是否已经运行了脚本。我仍在学习 Ansible,并希望我能深入了解更好的实践。操作 XML 时的幂等性似乎特别麻烦。Ansible 的优雅之处在于,Ansible 在实施更改之前会自行进行检查。但是,如果我必须自己进行检查,那是我以前没有想到的解决方案。

答:

2赞 β.εηοιτ.βε 10/13/2023 #1

如果要使任务幂等,只需构造一个与要添加的内容相匹配的 XPath 表达式即可。然后在属性中使用它,以及可以省略的 –,因为它是参数的默认值。xpathstate: present

因此,有了任务:

- xml:
    path: web.xml
    xpath: >-
      /ns:web-app
      /ns:servlet[
      ns:servlet-class[text()="org.apache.catalina.servlets.DefaultServlet"]
      ]
      /ns:init-param[
      ns:param-name[text()="readonly"]
      and ns:param-value[text()="true"]
      ]
    pretty_print: true
    namespaces:
      ns: http://xmlns.jcp.org/xml/ns/javaee

您的 XML 最终是

<?xml version='1.0' encoding='UTF-8'?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>readonly</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <!-- Much more in actual web.xml -->
</web-app>

评论

0赞 shepster 10/13/2023
谢谢!这个 Ansible 比我的清晰得多。有一点皱纹。在我的实际文件中,有不止一个.我可以接受的一个解决方案是指定.但是,我想以 .我想我可以用父表达式来做到这一点。但是,尝试喜欢或抛出错误。建议?<servlet>/ns:servlet[1]<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>/ns:parent::servlet-class[text()=\"org.apache.catalina.servlets.DefaultServlet\"]/ns:servlet-class[text()=\"org.apache.catalina.servlets.DefaultServlet\"]/ns:..
0赞 shepster 10/13/2023
我确实认识到,在我上面的例子中,我有不必要/不恰当地转义的引号。我已经尝试了正确使用并继续出现错误。text()="org.apache.catalina.servlets.DefaultServlet"
0赞 β.εηοιτ.βε 10/14/2023
您必须在表达式的 servlet 级别描述要面向的 servlet 节点的子节点。我相应地调整了 XPath 中的答案
0赞 shepster 10/24/2023
谢谢!我终于能够回到这个问题,您的解决方案正是我所需要的。感谢您展示令人钦佩的 Ansible/XML-fu