Repository: ansible/ansible

Issue:
Invalid params. Incorrect argument passed to function while sending
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
  - Bug Report

##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
Zabbix Host Addition
##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.2.0
  config file = None
  configured module search path = [u'/home/user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/.local/lib/python2.7/site-packages/ansible
  executable location = /home/user/.local/bin/ansible
  python version = 2.7.12 (default, Nov 20 2017, 18:23:56) [GCC 5.4.0 20160609]

```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
No change 
##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Ubuntu 16.04 LTS
##### SUMMARY
<!--- Explain the problem briefly -->
Trying to register hosts from ansible , I'm using few variables from ansible host file like host name, visible name etc. When I run the playbook it gives following error 
```
fatal: [10.10.140.9 -> localhost]: FAILED! => {"changed": false, "msg": "Failed to create host MY-PD-CT10: (u'Error -32602: Invalid params., Incorrect arguments passed to function. while sending {\"params\": {\"status\": 0, \"host\": \"MY-PD-CT10\", \"interfaces\": [{\"ip\": \"10.10.140.6\", \"main\": 1, \"type\": 1, \"useip\": 0}], \"groups\": [{\"groupid\": \"8\"}], \"name\": \"MY-PD-CT10\"}, \"jsonrpc\": \"2.0\", \"method\": \"host.create\", \"auth\": \"841578d0a278e720c0aa11820f8ee2b8\", \"id\": 4}', -32602)"}
fatal: [10.10.140.6 -> localhost]: FAILED! => {"changed": false, "msg": "Failed to create host MY-PD-CT07: (u'Error -32602: Invalid params., Incorrect arguments passed to function. while sending {\"params\": {\"status\": 0, \"host\": \"MY-PD-CT07\", \"interfaces\": [{\"ip\": \"10.10.140.6\", \"main\": 1, \"type\": 1, \"useip\": 0}], \"groups\": [{\"groupid\": \"8\"}], \"name\": \"MY-PD-CT07\"}, \"jsonrpc\": \"2.0\", \"method\": \"host.create\", \"auth\": \"dd9000292d17d06f3de872d58a2b4952\", \"id\": 4}', -32602)"}
```
##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml

---
- hosts: containers
  remote_user: daedalus
  vars:
    ipAdd: "{{inventory_hostname}}"
  tasks:
   - name: Create a new host or update an existing host's info
     local_action:
        module: zabbix_host
        server_url: http://10.10.140.18/zabbix
        login_user: Admin
        login_password: zabbix
        host_name: "{{ctHostname}}"
        visible_name: "{{ctHostname}}"
        host_groups:
         - Home-vLAN
        interfaces:
         - type: 1
           main: 1
           useip: 0
           ip: '10.10.140.6'
        proxy: ""


```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
It should have added the host in zabbix
##### ACTUAL RESULTS



Discussion:
Files identified in the description:
None

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Sorry, I did not see this report before; the issue tracker did not know it was about zabbix_host, unfortunately.

This is both a bug and not a bug; it's a bug because the ansible_host module could have caught the error (or even corrected with defaults), and not a bug because Zabbix requires the fields dns and ip to be set on a host interface definition (compare https://www.zabbix.com/documentation/3.4/manual/api/reference/hostinterface/object#host_interface). So if you add
`dns: something` to your interface definition, Zabbix will accept your interface definition; in the playbook you submitted that is probably a good idea since you also set useip to 0, so a dns name is actually required.

I will add a check for this to the zabbix_host module. An immediate workaround for you is to add 'dns' to the interface definition.
!component=lib/ansible/modules/monitoring/zabbix/zabbix_host.py
Files identified in the description:
* [lib/ansible/modules/monitoring/zabbix/zabbix_host.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/monitoring/zabbix/zabbix_host.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @D3DeFi @cove @harrisongu
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/monitoring/zabbix/zabbix_host.py b/lib/ansible/modules/monitoring/zabbix/zabbix_host.py
--- a/lib/ansible/modules/monitoring/zabbix/zabbix_host.py
+++ b/lib/ansible/modules/monitoring/zabbix/zabbix_host.py
@@ -81,9 +81,11 @@
     interfaces:
         description:
             - List of interfaces to be created for the host (see example below).
-            - 'Available values are: dns, ip, main, port, type and useip.'
+            - 'Available keys are: I(dns), I(ip), I(main), I(port), I(type), I(useip), and I(bulk).'
             - Please review the interface documentation for more information on the supported properties
             - 'https://www.zabbix.com/documentation/2.0/manual/appendix/api/hostinterface/definitions#host_interface'
+            - If an interface definition is incomplete, this module will attempt to fill in sensible values.
+            - I(type) can also be C(agent), C(snmp), C(ipmi), or C(jmx) instead of its numerical value.
         default: []
     tls_connect:
         description:
@@ -716,7 +718,37 @@ def main():
 
     ip = ""
     if interfaces:
+        # ensure interfaces are well-formed
         for interface in interfaces:
+            if 'type' not in interface:
+                module.fail_json(msg="(interface) type needs to be specified for interface '%s'." % interface)
+            interfacetypes = {'agent': 1, 'snmp': 2, 'ipmi': 3, 'jmx': 4}
+            if interface['type'] in interfacetypes.keys():
+                interface['type'] = interfacetypes[interface['type']]
+            if interface['type'] < 1 or interface['type'] > 4:
+                module.fail_json(msg="Interface type can only be 1-4 for interface '%s'." % interface)
+            if 'useip' not in interface:
+                interface['useip'] = 0
+            if 'dns' not in interface:
+                if interface['useip'] == 0:
+                    module.fail_json(msg="dns needs to be set if useip is 0 on interface '%s'." % interface)
+                interface['dns'] = ''
+            if 'ip' not in interface:
+                if interface['useip'] == 1:
+                    module.fail_json(msg="ip needs to be set if useip is 1 on interface '%s'." % interface)
+                interface['ip'] = ''
+            if 'main' not in interface:
+                interface['main'] = 0
+            if 'port' not in interface:
+                if interface['type'] == 1:
+                    interface['port'] = "10050"
+                elif interface['type'] == 2:
+                    interface['port'] = "161"
+                elif interface['type'] == 3:
+                    interface['port'] = "623"
+                elif interface['type'] == 4:
+                    interface['port'] = "12345"
+
             if interface['type'] == 1:
                 ip = interface['ip']
 


Test patch: