spring-bootansibleredhat

Ansible - Unarchive specifics files from war archive


I would like to extract two files from directory from war archive.

The two files exists in /WEB-INF/classes/

I have tried:

- name: create application.properties in /tmp
  unarchive:
    src: "/application/webapps/application.war"
    dest: "/tmp"
    remote_src: yes
    extra_opts:
      - -j
      - WEB-INF/classes/application.properties
      - WEB-INF/classes/logback.xml

Error :

"err":"unzip: cannot find or open /WEB-INF/classes/application.properties"

But it doesn't work of course. Any idea?


Solution

  • Really it looks like Ansible unarchive module is not meant of this specific use case.
    And there is a feature request to actually implement this exact feature.

    Long story short: extra_opts is meant for options, but does not seems be be meant for extra parameters.

    What you are looking to do seems like it was possible before this commit, indeed, before this commit, Ansible would do:

    cmd = [ self.cmd_path, '-o', self.src ]
    if self.opts:
        cmd.extend(self.opts)
    

    And so you will end with the command:

    unzip -o /application/webapps/application.war -j \
      WEB-INF/classes/application.properties \
      WEB-INF/classes/logback.xml
    

    That should have worked in your use case.
    But after this commit, Ansible's code ends up being

    cmd = [ self.cmd_path, '-o' ]
    if self.opts:
        cmd.extend(self.opts)
    cmd.append(self.src)
    

    And so, it generates this buggy unzip command:

    unzip -o -j \
      WEB-INF/classes/application.properties \
      WEB-INF/classes/logback.xml \
      /application/webapps/application.war
    

    Now you could work around this bug, but this will make unzip error, and we will have to sweep this error under the rug, so this should not be the solution of your choice.

    But here is the train of thought I went in and what I did to have a working playbook: I identified the issue with the command using ansible-playbook play.yml -vvvv, that got me the full unzip command issued by Ansible — the error below has been reduced for brevity:

    fatal: [localhost]: FAILED! => {
        "changed": false,
        "dest": "/tmp/out",
        "extract_results": {
            "cmd": [
                "/usr/bin/unzip",
                "-o",
                "-j",
                "WEB-INF/classes/application.properties",
                "WEB-INF/classes/logback.xml",
                "test.war",
                "-d",
                "/tmp/out"
            ]
        }
    }
    

    Based on this, I tricked the extra_opts by reproducing the archive in the src parameter, so it fits right after the option -j in the command.

    The drawback of this is that is is now generating this command:

    unzip -o -j \
      test.war \
      WEB-INF/classes/application.properties \
      WEB-INF/classes/logback.xml \
      test.war
    

    Which means that it is now trying to find the file test.war inside itself, and so, it will error because of this.

    Here is the errors this yields:

    "err": "caution: filename not matched: test.war\n"

    So once again, I used a trick with the help of failed_when to ignore this error, knowing the error it would yield me.

    So, given:

    $ tree ./WEB-INF
    ./WEB-INF
    └── classes
        ├── application.properties
        ├── ignore-me.txt
        └── logback.xml
    
    1 directory, 3 files
    
    $ tree /tmp
    /tmp
    
    0 directories, 0 files
    

    And the tasks:

     - shell: /usr/lib/jvm/java-1.8-openjdk/bin/jar -cf test.war *
    
    - file:
        path: /tmp/out
        state: directory
    
    - unarchive: 
        src: test.war
        dest: /tmp/out
        remote_src: yes
        extra_opts:
          - -j
          - test.war
          - WEB-INF/classes/application.properties
          - WEB-INF/classes/logback.xml
      register: extract
      failed_when: 
        - extract.extract_results.rc != 0
        - "extract.extract_results.err != 'caution: filename not matched:  ' 
            ~ extract.src ~ '\n'"
    
    

    You end up with those files:

    
    /ansible # tree /tmp/out
    /tmp/out
    ├── application.properties
    └── logback.xml
    
    0 directories, 2 files