I am trying to remediate V-222934 (Additional information at Tomcat Default Servlet Reference)
Starting with the web.xml
file:
<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>
I want to end with
<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>
I started with the following 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
But that threw an error complaining about a list rather than bytes/unicode.
Switching to input_type: xml
I get some success:
- 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
Which works but is not indempotent.
My big/primary question is: how do I make this idempotent?
Moreover, in my actual file there are more than one <servlet>
. A solution I can live with is to specify /ns:servlet[1]
. However, I would like to target the one with the <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
.
I have a minor question of: how can I get the yaml input type to work? (I think the code looks cleaner and makes more sense with that formatting.)
And lastly: I only know enough about namespaces to make the Ansible work. If someone has a cleaner/clearer way of writing the code, I am open to any improvements.
If you want to make your task idempotent, just construct a XPath expression that matches what you are looking to add. Then use that in the xpath
attribute, along with the state: present
– which can be omitted since it is the default of the parameter.
So with the task:
- 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
Your XML ends up being
<?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>