```Ansibledoes not have a rpm`` module.
That's right, because there is  yum.
Since it is a configuration management tool,  rpm that can be called  --force is deprecated in `ʻAnsible``.
However, there are some sites that have been developing past systems by splicing them together, and there are times when you really want to put a 32-bit  rpm in a 64-bit machine. When I implement this with  yum, it says "I will not put it in because there is a 64-bit package".
The ideal form is development with configuration management in mind, This is a deprecated module. </ font>
I'm not going to do it so difficult
--The  rpm file has already been placed on the node with  copy etc.
--I want to be able to place files with a built-in equivalent to  copy someday.
--Receive the option of the  rpm command and use it as it is
――I want to manage the flag someday
--Confirm that the specified  rpm file exists
--Confirm that the specified  rpm is not installed
--Install the specified  rpm together with the specified options
Is it about this?
See past articles.
-Ansible self-made module creation-Part 1: Life you want to receive arguments-
rpm.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ansible.module_utils.basic import AnsibleModule
#Main processing
#-----------------------------------------------------------
def main():
    #AnsibleModule class:Create module
    module = AnsibleModule(
        #Argument reception
        argument_spec=dict(
            #Write the argument receiving process here
        ),
        #Argument check enabled
        supports_check_mode=True
    )
    #Check for the existence of the specified file
    #Judgment of necessity of change
    changed = False
    #rpm installation
    #End processing
if __name__ == '__main__':
    main()
I wonder if this is the place
The arguments accepted this time are as follows
| Argument name | Mandatory | Default value | Argument meaning | 
|---|---|---|---|
| pkgs | ○ | - | List of packages | 
| opts | -Uvh | Options given to the rpm command | |
| chdir | / | Package storage directory | 
By the way, I didn't know how to receive the `` list'', so I posted it to a certain Q & A, but the next day I solved it myself. Reference: To use the array passed in Ansible with_list for a loop in a module
rpm.py
:#(abridgement)
#Argument reception
argument_spec=dict(
    #Package list(Mandatory,list type)
    pkgs = dict(required = True, type = list),
    #option(str type,[-Uvh])
    opts = dict(required = False, type = str, default = '-Uvh'),
    #Package storage directory(str type)
    chdir = dict(required = False, type = str, default = '/'),
),
#Argument check enabled
supports_check_mode=True
:#(abridgement)
In addition, indentation at the beginning of the line is deleted when excerpting partially as described above. Because it will be long sideways.
Last time, when I created a module to  mkfifo, I used the  stat command and the  test command without thinking about anything, but I thought that there would be so many modules.
Reference: Check the existence of the file with python
rpm.py
:#(abridgement)
from ansible.module_utils.basic import AnsibleModule
import os
:#(abridgement)
#Since it becomes redundant, re-enter variables
pkgs = module.params['pkgs']
chdir = module.params['chdir']
#Loop for each package list
for pkg in pkgs:
    #Check for the existence of the specified file
    if (os.path.isfile(chdir + '/' + pkg)):
        #File is not placed
        module.fail_json(msg = chdir + '/' + pkg + ' is not found.')
:#(abridgement)
I'm worried, so let's check the operation here. I haven't placed  rpm in / tmp / yet.
test.yml
- name: ntp install
  rpm:
    pkgs: '{{ item }}'
    opts: '-ivh'
    chdir: '/tmp'
  with_list:
    - [ 'ntp-4.2.6p5-15.el6.centos.x86_64.rpm','ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm' ]
Operation check
$ ansible-playbook -i test_grp -l test_srv -u root test.yml -vvv
:#(abridgement)
ok: [192.168.56.104] => (item=[u'ntp-4.2.6p5-15.el6.centos.x86_64.rpm', u'ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm']) => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "invocation": {
        "module_args": {
            "chdir": "/tmp",
            "opts": "-ivh",
            "pkgs": [
                "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
                "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
            ]
        }
    },
    "item": [
        "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
        "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
    ]
}
That ... a little debug.
rpm.py
#Since it becomes redundant, re-enter variables
pkgs = module.params['pkgs']
chdir = module.params['chdir']
num = 0
hog = 0
#Loop for each package list
for pkg in pkgs:
    num += 1
    #Check for the existence of the specified file
    if (os.path.isfile(chdir + '/' + pkg)):
        hog += 1
        #File is not placed
        module.fail_json(msg = chdir + '/' + pkg + ' is not found.')
:#(abridgement)
module.exit_json(num = num, hog = hog)
Execution result
ok: [192.168.56.104] => (item=[u'ntp-4.2.6p5-15.el6.centos.x86_64.rpm', u'ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm']) => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "hog": 0,  ★
    "invocation": {
        "module_args": {
            "chdir": "/tmp",
            "opts": "-ivh",
            "pkgs": [
                "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
                "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
            ]
        }
    },
    "item": [
        "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
        "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
    ],
    "num": 2  ★
}
Hmmm ʻif (os.path.isfile (chdir +'/' + pkg)): I wonder if `` is wrong. As a result of various trials, it worked as ʻif os.path.isfile (chdir +'/' + pkg) == False: ``. Hmm, why?
rpm.py
:#(abridgement)
from ansible.module_utils.basic import AnsibleModule
import os
:#(abridgement)
#Since it becomes redundant, re-enter variables
pkgs = module.params['pkgs']
chdir = module.params['chdir']
#Loop for each package list
for pkg in pkgs:
    #Check for the existence of the specified file
    if os.path.isfile(chdir + '/' + pkg) == False:
        #File is not placed
        module.fail_json(msg = chdir + '/' + pkg + ' is not found.')
:#(abridgement)
You don't need to change it, that is, if you already have all the  pkg installed. You can tell if the  rpm package is installed with the following command.
$ rpm -q ntp-4.2.6p5-15.el6.centos.x86_64
ntp-4.2.6p5-15.el6.centos.x86_64
$ echo $?
0
$ rpm -q hoge
Package hoge is not installed.
$ echo $?
1
However, the  rpm file is not always the package name without the  .rpm at the end of the file name.
$ ls -1 jdk-8u192-linux-x64.rpm
jdk-8u192-linux-x64.rpm
$ rpm -q jdk-8u192-linux-x64
Package jdk-8u192-linux-x64 is not installed.
$ rpm -qa | grep jdk
jdk1.8-1.8.0_192-fcs.x86_64
In the above example, the file name is  jdk-8u192-linux-x64.rpm, but the package name is  jdk1.8-1.8.0_192-fcs.x86_64.
To determine this, you need to look up the package name with rpm -qp rpm filename.
$ rpm -qp jdk-8u192-linux-x64.rpm
warning: jdk-8u192-linux-x64.rpm:Header V3 RSA/SHA256 Signature, key ID ec551f03: NOKEY
jdk1.8-1.8.0_192-fcs.x86_64
The package name is obtained from the above standard output.
Incorporate this process into the module
rpm.py
:#(abridgement)
#Since it becomes redundant, re-enter variables
pkgs = module.params['pkgs']
chdir = module.params['chdir']
#Judgment of necessity of change
changed = False
#List of rpm files to be installed
rpms = []
#Loop for each package list
for pkg in pkgs:
    #Create full path of file
    fpath = chdir + '/' + pkg
    #Check for the existence of the specified file
    if os.path.exists(fpath) == False:
        #File is not placed
        module.fail_json(msg = fpath + ' is not found.')
    #Get the package name from the rpm file
    rc, pkg_name, stderr = module.run_command('rpm -qp ' + fpath)
    #Check the installation status of the package
    rc, stdout, stderr = module.run_command('rpm -q ' + pkg_name)
    #Is it installed
    if rc != 0:
        #Not installed, so change required
        changed = True
        #Add to installation target
        rpms.append(fpath)
:#(abridgement)
If the rpm list  rpms to be installed is empty, it will end ... It will be left to  chagned! = True.
rpm.py
:#(abridgement)
#Judgment of necessity of rpm installation
if changed != True:
    #Not to be installed
    module.exit_json()
#rpm list creation
rpm_line = ' '.join(rpms)
#rpm installation
rc, stdout, stderr = module.run_command('rpm ' + module.params['opts'] + ' ' + rpm_line)
#rpm installation result judgment
if rc != 0:
    #Installation failure
    module.fail_json(stdout = stdout, stderr = stderr)
#End processing
module.exit_json(changed = changed)
:#(abridgement)
test.yml
- name: ntp install
  rpm:
    pkgs: '{{ item }}'
    opts: '-ivh'
    chdir: '/tmp'
  with_list:
    - [ 'ntp-4.2.6p5-15.el6.centos.x86_64.rpm','ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm' ]
#Make sure the package file is in place
$ ssh [email protected] "ls -l /tmp/*rpm"
-rw-rw-r--.1 root root 614364 May 11 17:01 2020 /tmp/ntp-4.2.6p5-15.el6.centos.x86_64.rpm
-rw-rw-r--.1 root root 80836 May 11 17:00 2020 /tmp/ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm
#Make sure the package file is not installed
$ ssh [email protected] "rpm -qa | grep ntp"
$
#Run!
$ ansible-playbook -i test_grp -l test_srv -u root test.yml -vvv
:#(abridgement)
changed: [192.168.56.104] => (item=[u'ntp-4.2.6p5-15.el6.centos.x86_64.rpm', u'ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm']) => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "ansible_loop_var": "item",
    "changed": true,
    "invocation": {
        "module_args": {
            "chdir": "/tmp",
            "opts": "-ivh",
            "pkgs": [
                "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
                "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
            ]
        }
    },
    "item": [
        "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
        "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
    ],
    "msg": "/tmp/ntp-4.2.6p5-15.el6.centos.x86_64.rpm /tmp/ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
}
#Run again to check idempotence!
$ ansible-playbook -i test_grp -l test_srv -u root test.yml -vvv
ok: [192.168.56.104] => (item=[u'ntp-4.2.6p5-15.el6.centos.x86_64.rpm', u'ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm']) => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "invocation": {
        "module_args": {
            "chdir": "/tmp",
            "opts": "-ivh",
            "pkgs": [
                "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
                "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
            ]
        }
    },
    "item": [
        "ntp-4.2.6p5-15.el6.centos.x86_64.rpm",
        "ntpdate-4.2.6p5-15.el6.centos.x86_64.rpm"
    ]
}
Isn't it okay?
rpm.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ansible.module_utils.basic import AnsibleModule
import os
#Main processing
#-----------------------------------------------------------
def main():
    #AnsibleModule class:Create module
    module = AnsibleModule(
        #Argument reception
        argument_spec=dict(
            #Package list(Mandatory,list type)
            pkgs = dict(required = True, type = list),
            #option(str type,[-Uvh])
            opts = dict(required = False, type = str, default = '-Uvh'),
            #Package storage directory(str type)
            chdir = dict(required = False, type = str, default = '/'),
        ),
        #Argument check enabled
        supports_check_mode=True
    )
    #Since it becomes redundant, re-enter variables
    pkgs = module.params['pkgs']
    chdir = module.params['chdir']
    #Judgment of necessity of change
    changed = False
    #List of rpm files to be installed
    rpms = []
    #Loop for each package list
    for pkg in pkgs:
        #Create full path of file
        fpath = chdir + '/' + pkg
        #Check for the existence of the specified file
        if os.path.exists(fpath) == False:
            #File is not placed
            module.fail_json(msg = fpath + ' is not found.')
        #Get the package name from the rpm file
        rc, pkg_name, stderr = module.run_command('rpm -qp ' + fpath)
        #Check the installation status of the package
        rc, stdout, stderr = module.run_command('rpm -q ' + pkg_name)
        #Is it installed
        if rc != 0:
            #Not installed, so change required
            changed = True
            #Add to installation target
            rpms.append(fpath)
    #Judgment of necessity of rpm installation
    if changed != True:
        #Not to be installed
        module.exit_json()
    #rpm list creation
    rpm_line = ' '.join(rpms)
    #rpm installation
    rc, stdout, stderr = module.run_command('rpm ' + module.params['opts'] + ' ' + rpm_line)
    #rpm installation result judgment
    if rc != 0:
        #Installation failure
        module.fail_json(stdout = stdout, stderr = stderr)
    #End processing
    module.exit_json(changed = changed)
if __name__ == '__main__':
    main()