I have a file confluence.cfg.xml with the following structure
<?xml version='1.0' encoding='UTF-8'?>
<confluence-configuration>
<setupStep>setupstart</setupStep>
<setupType>custom</setupType>
<buildNumber>0</buildNumber>
<properties>
<property name="confluence.database.choice">postgresql</property>
<property name="confluence.database.connection.type">database-type-standard</property>
<property name="webwork.multipart.saveDir">${localHome}/temp</property>
<property name="attachments.dir">${confluenceHome}/attachments</property>
</properties>
</confluence-configuration>
I want to add and remove multiple <property>
elements. However I am not getting the syntax right. Here I am trying to remove two of the elements (the code runs but removes every <property>
elements rather than just the two I want):
- name: "Remove elements"
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: /confluence-configuration/properties/property
attribute: name
value:
- confluence.database.choice
- confluence.database.connection.type
state: absent
And here I am trying to add a single, say <property name="foo">bar</property>
element.
- name: "Add elements"
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: /confluence-configuration/properties
add_children:
- property: bar
- property:
name: foo
The above gives me two elements (<property>bar</property>
and <property name="foo"/>
), but I can't seem to specify both at the same time. And once I can specify an element properly, I'd like to be able to add a list of them.
CodePudding user response:
In order to remove nodes, you need to to have the right XPath, the value
won't be taken into consideration, this parameter is meant for the state: present
.
This said, XPath supports selecting a nodes via attributes and does also support or
expressions, so, your task to remove nodes can be written as:
- name: Remove elements
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: >-
/confluence-configuration
/properties
/property[
@name='confluence.database.choice'
or @name='confluence.database.connection.type'
]
state: absent
Regarding the addition of the node, once again, your attribute can be part of your XPath, if this XPath does not exists, then, Ansible will create it and assign the needed value:
- name: Add <property name="foo">bar</property>
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: /confluence-configuration/properties/property[@name='foo']
value: bar
Given the playbook
- hosts: localhost
gather_facts: no
vars:
atl_product_home: .
xml: |-
<?xml version='1.0' encoding='UTF-8'?>
<confluence-configuration>
<setupStep>setupstart</setupStep>
<setupType>custom</setupType>
<buildNumber>0</buildNumber>
<properties>
<property name="confluence.database.choice">
postgresql
</property>
<property name="confluence.database.connection.type">
database-type-standard
</property>
<property name="webwork.multipart.saveDir">
${localHome}/temp
</property>
<property name="attachments.dir">
${confluenceHome}/attachments
</property>
</properties>
</confluence-configuration>
tasks:
- name: Create configuration file
copy:
content: "{{ xml }}"
dest: "{{ atl_product_home }}/confluence.cfg.xml"
- name: Remove elements
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: >-
/confluence-configuration
/properties
/property[
@name='confluence.database.choice'
or @name='confluence.database.connection.type'
]
state: absent
- name: Add <property name="foo">bar</property>
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: /confluence-configuration/properties/property[@name='foo']
value: bar
- debug:
var: lookup('file', atl_product_home ~ '/confluence.cfg.xml')
This yields:
PLAY [localhost] **************************************************************
TASK [Create configuration file] **********************************************
changed: [localhost]
TASK [Remove elements] ********************************************************
changed: [localhost]
TASK [Add <property name="foo">bar</property>] ********************************
changed: [localhost]
TASK [debug] ******************************************************************
ok: [localhost] =>
lookup('file', atl_product_home ~ '/confluence.cfg.xml'): |-
<?xml version='1.0' encoding='UTF-8'?>
<confluence-configuration>
<setupStep>setupstart</setupStep>
<setupType>custom</setupType>
<buildNumber>0</buildNumber>
<properties>
<property name="webwork.multipart.saveDir">
${localHome}/temp
</property>
<property name="attachments.dir">
${confluenceHome}/attachments
</property>
<property name="foo">bar</property></properties>
</confluence-configuration>
PLAY RECAP ********************************************************************
localhost : ok=4 changed=3
CodePudding user response:
Thank you, β.εηοιτ.βε!
The only thing missing was the ability to add multiple elements at once. Taking your example, the solution for me is:
- name: "Remove elements from {{ atl_product_home }}/confluence.cfg.xml"
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: >-
/confluence-configuration
/properties
/property[
@name='confluence.database.choice'
or @name='confluence.database.connection.type'
]
state: absent
- name: "Add elements to {{ atl_product_home }}/confluence.cfg.xml"
xml:
path: "{{ atl_product_home }}/confluence.cfg.xml"
xpath: "/confluence-configuration/properties/property[@name='{{ item.attribute }}']"
value: "{{ item.value }}"
pretty_print: true
loop:
- { attribute: 'access.mode', value: 'READ_WRITE' }
- { attribute: 'admin.ui.allow.daily.backup.custom.location', value: 'false' }