a )g+5@sddlmZmZmZeZdZdZddlZddl Z ddl Z ddl m Z ddl mZddlmZmZdd Zd d Zd d ZedkredS))absolute_importdivisionprint_functiona --- module: blockinfile short_description: Insert/update/remove a text block surrounded by marker lines version_added: '2.0' description: - This module will insert/update/remove a block of multi-line text surrounded by customizable marker lines. author: - Yaegashi Takeshi (@yaegashi) options: path: description: - The file to modify. - Before Ansible 2.3 this option was only usable as I(dest), I(destfile) and I(name). type: path required: yes aliases: [ dest, destfile, name ] state: description: - Whether the block should be there or not. type: str choices: [ absent, present ] default: present marker: description: - The marker line template. - C({mark}) will be replaced with the values in C(marker_begin) (default="BEGIN") and C(marker_end) (default="END"). - Using a custom marker without the C({mark}) variable may result in the block being repeatedly inserted on subsequent playbook runs. - Multi-line markers are not supported and will result in the block being repeatedly inserted on subsequent playbook runs. - A newline is automatically appended by the module to C(marker_begin) and C(marker_end). type: str default: '# {mark} ANSIBLE MANAGED BLOCK' block: description: - The text to insert inside the marker lines. - If it is missing or an empty string, the block will be removed as if C(state) were specified to C(absent). type: str default: '' aliases: [ content ] insertafter: description: - If specified and no begin/ending C(marker) lines are found, the block will be inserted after the last match of specified regular expression. - A special value is available; C(EOF) for inserting the block at the end of the file. - If specified regular expression has no matches, C(EOF) will be used instead. - The presence of the multiline flag (?m) in the regular expression controls whether the match is done line by line or with multiple lines. This behaviour was added in ansible-core 2.14. type: str choices: [ EOF, '*regex*' ] default: EOF insertbefore: description: - If specified and no begin/ending C(marker) lines are found, the block will be inserted before the last match of specified regular expression. - A special value is available; C(BOF) for inserting the block at the beginning of the file. - If specified regular expression has no matches, the block will be inserted at the end of the file. - The presence of the multiline flag (?m) in the regular expression controls whether the match is done line by line or with multiple lines. This behaviour was added in ansible-core 2.14. type: str choices: [ BOF, '*regex*' ] create: description: - Create a new file if it does not exist. type: bool default: no backup: description: - Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly. type: bool default: no marker_begin: description: - This will be inserted at C({mark}) in the opening ansible block marker. type: str default: BEGIN version_added: '2.5' marker_end: required: false description: - This will be inserted at C({mark}) in the closing ansible block marker. type: str default: END version_added: '2.5' notes: - When using 'with_*' loops be aware that if you do not set a unique mark the block will be overwritten on each iteration. - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well. - Option I(follow) has been removed in Ansible 2.5, because this module modifies the contents of the file so I(follow=no) doesn't make sense. - When more then one block should be handled in one file you must change the I(marker) per task. extends_documentation_fragment: - action_common_attributes - action_common_attributes.files - files - validate attributes: check_mode: support: full diff_mode: support: full safe_file_operations: support: full platform: support: full platforms: posix vault: support: none a # Before Ansible 2.3, option 'dest' or 'name' was used instead of 'path' - name: Insert/Update "Match User" configuration block in /etc/ssh/sshd_config ansible.builtin.blockinfile: path: /etc/ssh/sshd_config block: | Match User ansible-agent PasswordAuthentication no - name: Insert/Update eth0 configuration stanza in /etc/network/interfaces (it might be better to copy files into /etc/network/interfaces.d/) ansible.builtin.blockinfile: path: /etc/network/interfaces block: | iface eth0 inet static address 192.0.2.23 netmask 255.255.255.0 - name: Insert/Update configuration using a local file and validate it ansible.builtin.blockinfile: block: "{{ lookup('ansible.builtin.file', './local/sshd_config') }}" path: /etc/ssh/sshd_config backup: yes validate: /usr/sbin/sshd -T -f %s - name: Insert/Update HTML surrounded by custom markers after line ansible.builtin.blockinfile: path: /var/www/html/index.html marker: "" insertafter: "" block: |

Welcome to {{ ansible_hostname }}

Last updated on {{ ansible_date_time.iso8601 }}

- name: Remove HTML as well as surrounding markers ansible.builtin.blockinfile: path: /var/www/html/index.html marker: "" block: "" - name: Add mappings to /etc/hosts ansible.builtin.blockinfile: path: /etc/hosts block: | {{ item.ip }} {{ item.name }} marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.name }}" loop: - { name: host1, ip: 10.10.1.10 } - { name: host2, ip: 10.10.1.11 } - { name: host3, ip: 10.10.1.12 } - name: Search with a multiline search flags regex and if found insert after blockinfile: path: listener.ora block: "{{ listener_line | indent(width=8, first=True) }}" insertafter: '(?m)SID_LIST_LISTENER_DG =\n.*\(SID_LIST =' marker: " " N)b) AnsibleModule)to_bytes to_nativec Cstj|jd\}}t|d}||||jdd}| }|rd|vr`|j d|d| ||\}} } |dk}|dkr|j d|| fd|r|j |||jd d dS) N)dirwbvalidatez%szvalidate must contain %%s: %smsgrz"failed to validate: rc:%s error:%s unsafe_writes)r) tempfileZmkstempZtmpdirosfdopenwritecloseparamsget fail_jsonZ run_commandZ atomic_move) modulecontentspathZtmpfdZtmpfilefr Zvalidrcouterrr?/usr/lib/python3.9/site-packages/ansible/modules/blockinfile.py write_changess"  r cCs<||j}|j|d|dr4|r(|d7}d}|d7}||fS)NF)diffz and Tz,ownership, perms or SE linux context changed)Zload_file_common_argumentsrZ set_file_attributes_if_different)rchangedmessager!Z file_argsrrrcheck_file_attrss r$cCstttddgddtddddgdtdd d tdd d gd tddtddtddd tddd tddtddd tddd d ddggddd}|j}|d}tj|r|jdd|dtj|}|sp||ds|jdd|dtj |}tj|sf|j sfzt |WnDt yd}z*|jd||d|dfd WYd}~n d}~00d}g}n>t |d!}|}Wdn1s0Y|d}d d d"|d"|d#} |jr|r|| d$<|d} |d} t|d%} t|d&} |d'dk}|s,|s,|jdd(|d)| durD| durDd*} | d+vrbtt| d,d-}n"| d.vrtt| d,d-}nd}ttd/t|d0| ttj}ttd/t|d1| ttj}|r| r| ttjs| ttj7} |g| d|g}ng}d}}t|D]&\}}||kr:|}||kr$|}q$d||fvr(d}|dur|jtj@r||}|r| rt|d2d|}n| rt|d2d| }n$t|D]\}}||r|}q|durt!|}n| dur&|d7}n| durd}nt!|}n0||krDg|||d<ng|||d<|}|dkr||dttjs||dttj7<||||<|rd3"|}nd3}|jr|| d4<||krd }d}n,|durd5}d}n|sd6}d}nd7}d}d}|rV|j sV||d8r:|r:|#|}tj$|d}t%||||j rt|st|j||| d9i}t&||||\}}d:||d;<d:||d<<| |g}|dur|j|||d9n|j||||d=dS)>NrT)destZdestfilename)typerequiredaliasesstrpresentZabsent)r'defaultchoicesz# {mark} ANSIBLE MANAGED BLOCK)r'r,Zcontent)r'r,r))r'boolFZBEGINZEND) rstatemarkerblock insertafter insertbeforecreatebackupr marker_begin marker_endr4r3)Z argument_specZmutually_exclusiveZadd_file_common_argsZsupports_check_modezPath %s is a directory !)rr r5izPath %s does not exist !z6Error creating %s Error code: %s Error description: %srr rbz %s (content))beforeafter before_header after_headerr<r2r1r0zFile %s not present)r"r EOF)Nr@Zsurrogate_or_strict)errors)NZBOFz{mark}r7r8 r=z File createdz Block removedzBlock insertedr6)r"r r!z%s (file attributes)r>r?)r"r r! backup_file)'rdictrrrisdirrexistsZbooleandirnameZ check_modemakedirs Exceptionopenread splitlinesZ_diffrZ exit_jsonrecompilesubrlinesependswith enumerateflags MULTILINEsearchrcountendstartlenjoinZ backup_localrealpathr r$)rrrZ path_existsZdestpatheoriginallinesrr!r4r3r2r1r+ZinsertreZmarker0Zmarker1Z blocklinesZn0Zn1ilinematchresultr r"rDZ real_pathZ attr_diffZdifflistrrrmains         4 (       $$                       rd__main__)Z __future__rrrr'Z __metaclass__Z DOCUMENTATIONZEXAMPLESrNrrZansible.module_utils.sixrZansible.module_utils.basicrZansible.module_utils._textrrr r$rd__name__rrrrsj<   (